feat(12-01): create decompose output schema
- Add TaskBreakdown type with number, name, description, type, dependencies - Create decomposeOutputSchema discriminated union (questions/decompose_complete/error) - Create decomposeOutputJsonSchema for Claude CLI --json-schema flag - Update module docstring to include decompose mode
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
* - execute: Standard task execution (done/questions/error)
|
* - execute: Standard task execution (done/questions/error)
|
||||||
* - discuss: Gather context through questions, output decisions
|
* - discuss: Gather context through questions, output decisions
|
||||||
* - breakdown: Decompose initiative into phases
|
* - breakdown: Decompose initiative into phases
|
||||||
|
* - decompose: Decompose phase into individual tasks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@@ -61,6 +62,30 @@ const phaseBreakdownSchema = z.object({
|
|||||||
|
|
||||||
export type PhaseBreakdown = z.infer<typeof phaseBreakdownSchema>;
|
export type PhaseBreakdown = z.infer<typeof phaseBreakdownSchema>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task type enum - mirrors database task.type column.
|
||||||
|
*/
|
||||||
|
const taskTypeSchema = z.enum([
|
||||||
|
'auto',
|
||||||
|
'checkpoint:human-verify',
|
||||||
|
'checkpoint:decision',
|
||||||
|
'checkpoint:human-action',
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task from decompose output.
|
||||||
|
* Prompt instructs: { "number": 1, "name": "...", "description": "...", "type": "auto", "dependencies": [0] }
|
||||||
|
*/
|
||||||
|
const taskBreakdownSchema = z.object({
|
||||||
|
number: z.number().int().positive(),
|
||||||
|
name: z.string().min(1),
|
||||||
|
description: z.string(),
|
||||||
|
type: taskTypeSchema.default('auto'),
|
||||||
|
dependencies: z.array(z.number().int()).optional().default([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TaskBreakdown = z.infer<typeof taskBreakdownSchema>;
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// EXECUTE MODE SCHEMA (default)
|
// EXECUTE MODE SCHEMA (default)
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -346,3 +371,105 @@ export const breakdownOutputJsonSchema = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// DECOMPOSE MODE SCHEMA
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompose mode output schema.
|
||||||
|
* Agent asks questions OR completes with tasks.
|
||||||
|
*
|
||||||
|
* Prompt tells agent:
|
||||||
|
* - Output "questions" status when needing clarification
|
||||||
|
* - Output "decompose_complete" status with tasks array when done
|
||||||
|
*/
|
||||||
|
export const decomposeOutputSchema = z.discriminatedUnion('status', [
|
||||||
|
// Agent needs clarification
|
||||||
|
z.object({
|
||||||
|
status: z.literal('questions'),
|
||||||
|
questions: z.array(questionItemSchema),
|
||||||
|
}),
|
||||||
|
// Agent has decomposed phase into tasks
|
||||||
|
z.object({
|
||||||
|
status: z.literal('decompose_complete'),
|
||||||
|
tasks: z.array(taskBreakdownSchema),
|
||||||
|
}),
|
||||||
|
// Unrecoverable error
|
||||||
|
z.object({
|
||||||
|
status: z.literal('unrecoverable_error'),
|
||||||
|
error: z.string(),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export type DecomposeOutput = z.infer<typeof decomposeOutputSchema>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Schema for decompose mode (passed to Claude CLI --json-schema)
|
||||||
|
*/
|
||||||
|
export const decomposeOutputJsonSchema = {
|
||||||
|
type: 'object',
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
status: { const: 'questions' },
|
||||||
|
questions: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
question: { type: 'string' },
|
||||||
|
options: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
label: { type: 'string' },
|
||||||
|
description: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['label'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['id', 'question'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['status', 'questions'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
status: { const: 'decompose_complete' },
|
||||||
|
tasks: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { type: 'integer', minimum: 1 },
|
||||||
|
name: { type: 'string', minLength: 1 },
|
||||||
|
description: { type: 'string' },
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
enum: ['auto', 'checkpoint:human-verify', 'checkpoint:decision', 'checkpoint:human-action'],
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
type: 'array',
|
||||||
|
items: { type: 'integer' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['number', 'name', 'description'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['status', 'tasks'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
status: { const: 'unrecoverable_error' },
|
||||||
|
error: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['status', 'error'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user