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:
Lukas May
2026-02-01 11:34:31 +01:00
parent a1d13f10cd
commit 8ffa54a531

View File

@@ -8,6 +8,7 @@
* - execute: Standard task execution (done/questions/error)
* - discuss: Gather context through questions, output decisions
* - breakdown: Decompose initiative into phases
* - decompose: Decompose phase into individual tasks
*/
import { z } from 'zod';
@@ -61,6 +62,30 @@ const phaseBreakdownSchema = z.object({
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)
// =============================================================================
@@ -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'],
},
],
};