@posthog/agent 1.19.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-cli/cli.js +3197 -2675
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/adapters/claude/claude-adapter.d.ts +4 -3
- package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
- package/dist/src/adapters/claude/claude-adapter.js +149 -133
- package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
- package/dist/src/adapters/types.d.ts +9 -4
- package/dist/src/adapters/types.d.ts.map +1 -1
- package/dist/src/agent.d.ts +1 -1
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +9 -8
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/research.d.ts +1 -1
- package/dist/src/agents/research.d.ts.map +1 -1
- package/dist/src/agents/research.js +55 -5
- package/dist/src/agents/research.js.map +1 -1
- package/dist/src/file-manager.d.ts +12 -0
- package/dist/src/file-manager.d.ts.map +1 -1
- package/dist/src/file-manager.js +76 -10
- package/dist/src/file-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +2 -1
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +11 -0
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +25 -0
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +12 -4
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +271 -117
- package/dist/src/task-progress-reporter.js.map +1 -1
- package/dist/src/todo-manager.d.ts +29 -0
- package/dist/src/todo-manager.d.ts.map +1 -0
- package/dist/src/todo-manager.js +126 -0
- package/dist/src/todo-manager.js.map +1 -0
- package/dist/src/types.d.ts +17 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/workflow/config.d.ts.map +1 -1
- package/dist/src/workflow/config.js +11 -0
- package/dist/src/workflow/config.js.map +1 -1
- package/dist/src/workflow/steps/build.d.ts.map +1 -1
- package/dist/src/workflow/steps/build.js +10 -3
- package/dist/src/workflow/steps/build.js.map +1 -1
- package/dist/src/workflow/steps/finalize.d.ts +3 -0
- package/dist/src/workflow/steps/finalize.d.ts.map +1 -0
- package/dist/src/workflow/steps/finalize.js +173 -0
- package/dist/src/workflow/steps/finalize.js.map +1 -0
- package/dist/src/workflow/steps/plan.d.ts.map +1 -1
- package/dist/src/workflow/steps/plan.js +13 -6
- package/dist/src/workflow/steps/plan.js.map +1 -1
- package/dist/src/workflow/steps/research.js +3 -3
- package/dist/src/workflow/steps/research.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude/claude-adapter.ts +67 -48
- package/src/adapters/types.ts +10 -4
- package/src/agent.ts +17 -8
- package/src/agents/research.ts +55 -5
- package/src/file-manager.ts +89 -6
- package/src/posthog-api.ts +33 -1
- package/src/prompt-builder.ts +24 -0
- package/src/task-progress-reporter.ts +299 -138
- package/src/todo-manager.ts +169 -0
- package/src/types.ts +20 -1
- package/src/workflow/config.ts +11 -0
- package/src/workflow/steps/build.ts +12 -3
- package/src/workflow/steps/finalize.ts +207 -0
- package/src/workflow/steps/plan.ts +16 -6
- package/src/workflow/steps/research.ts +3 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
2
2
|
import { PLANNING_SYSTEM_PROMPT } from '../../agents/planning.js';
|
|
3
3
|
import { finalizeStepGitActions } from '../utils.js';
|
|
4
|
+
import { TodoManager } from '../../todo-manager.js';
|
|
4
5
|
|
|
5
6
|
const planStep = async ({ step, context }) => {
|
|
6
7
|
const { task, cwd, isCloudMode, options, logger, fileManager, gitManager, promptBuilder, adapter, mcpServers, emitEvent, } = context;
|
|
@@ -72,17 +73,23 @@ const planStep = async ({ step, context }) => {
|
|
|
72
73
|
prompt: fullPrompt,
|
|
73
74
|
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
74
75
|
});
|
|
76
|
+
const todoManager = new TodoManager(fileManager, stepLogger);
|
|
75
77
|
let planContent = '';
|
|
76
78
|
for await (const message of response) {
|
|
77
79
|
emitEvent(adapter.createRawSDKEvent(message));
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
emitEvent(
|
|
80
|
+
const transformedEvents = adapter.transform(message);
|
|
81
|
+
for (const event of transformedEvents) {
|
|
82
|
+
emitEvent(event);
|
|
81
83
|
}
|
|
84
|
+
const todoList = await todoManager.checkAndPersistFromMessage(message, task.id);
|
|
85
|
+
if (todoList) {
|
|
86
|
+
emitEvent(adapter.createArtifactEvent('todos', todoList));
|
|
87
|
+
}
|
|
88
|
+
// Extract text content for plan
|
|
82
89
|
if (message.type === 'assistant' && message.message?.content) {
|
|
83
|
-
for (const
|
|
84
|
-
if (
|
|
85
|
-
planContent += `${
|
|
90
|
+
for (const block of message.message.content) {
|
|
91
|
+
if (block.type === 'text' && block.text) {
|
|
92
|
+
planContent += `${block.text}\n`;
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sources":["../../../../src/workflow/steps/plan.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { PLANNING_SYSTEM_PROMPT } from '../../agents/planning.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\n\nexport const planStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('PlanStep');\n\n const existingPlan = await fileManager.readPlan(task.id);\n if (existingPlan) {\n stepLogger.info('Plan already exists, skipping step', { taskId: task.id });\n return { status: 'skipped' };\n }\n\n const researchData = await fileManager.readResearch(task.id);\n if (researchData?.questions && !researchData.answered) {\n stepLogger.info('Waiting for answered research questions', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));\n return { status: 'skipped', halt: true };\n }\n\n stepLogger.info('Starting planning phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'planning' }));\n let researchContext = '';\n if (researchData) {\n researchContext += `## Research Context\\n\\n${researchData.context}\\n\\n`;\n if (researchData.keyFiles.length > 0) {\n researchContext += `**Key Files:**\\n${researchData.keyFiles.map(f => `- ${f}`).join('\\n')}\\n\\n`;\n }\n if (researchData.blockers && researchData.blockers.length > 0) {\n researchContext += `**Considerations:**\\n${researchData.blockers.map(b => `- ${b}`).join('\\n')}\\n\\n`;\n }\n\n // Add answered questions if they exist\n if (researchData.questions && researchData.answers && researchData.answered) {\n researchContext += `## Implementation Decisions\\n\\n`;\n for (const question of researchData.questions) {\n const answer = researchData.answers.find(\n (a) => a.questionId === question.id\n );\n\n researchContext += `### ${question.question}\\n\\n`;\n if (answer) {\n researchContext += `**Selected:** ${answer.selectedOption}\\n`;\n if (answer.customInput) {\n researchContext += `**Details:** ${answer.customInput}\\n`;\n }\n } else {\n researchContext += `**Selected:** Not answered\\n`;\n }\n researchContext += `\\n`;\n }\n }\n }\n\n const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);\n const fullPrompt = `${PLANNING_SYSTEM_PROMPT}\\n\\n${planningPrompt}\\n\\n${researchContext}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, MCP resources, and ExitPlanMode\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'ExitPlanMode',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n let planContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const
|
|
1
|
+
{"version":3,"file":"plan.js","sources":["../../../../src/workflow/steps/plan.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { PLANNING_SYSTEM_PROMPT } from '../../agents/planning.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\nimport { TodoManager } from '../../todo-manager.js';\n\nexport const planStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('PlanStep');\n\n const existingPlan = await fileManager.readPlan(task.id);\n if (existingPlan) {\n stepLogger.info('Plan already exists, skipping step', { taskId: task.id });\n return { status: 'skipped' };\n }\n\n const researchData = await fileManager.readResearch(task.id);\n if (researchData?.questions && !researchData.answered) {\n stepLogger.info('Waiting for answered research questions', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));\n return { status: 'skipped', halt: true };\n }\n\n stepLogger.info('Starting planning phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'planning' }));\n let researchContext = '';\n if (researchData) {\n researchContext += `## Research Context\\n\\n${researchData.context}\\n\\n`;\n if (researchData.keyFiles.length > 0) {\n researchContext += `**Key Files:**\\n${researchData.keyFiles.map(f => `- ${f}`).join('\\n')}\\n\\n`;\n }\n if (researchData.blockers && researchData.blockers.length > 0) {\n researchContext += `**Considerations:**\\n${researchData.blockers.map(b => `- ${b}`).join('\\n')}\\n\\n`;\n }\n\n // Add answered questions if they exist\n if (researchData.questions && researchData.answers && researchData.answered) {\n researchContext += `## Implementation Decisions\\n\\n`;\n for (const question of researchData.questions) {\n const answer = researchData.answers.find(\n (a) => a.questionId === question.id\n );\n\n researchContext += `### ${question.question}\\n\\n`;\n if (answer) {\n researchContext += `**Selected:** ${answer.selectedOption}\\n`;\n if (answer.customInput) {\n researchContext += `**Details:** ${answer.customInput}\\n`;\n }\n } else {\n researchContext += `**Selected:** Not answered\\n`;\n }\n researchContext += `\\n`;\n }\n }\n }\n\n const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);\n const fullPrompt = `${PLANNING_SYSTEM_PROMPT}\\n\\n${planningPrompt}\\n\\n${researchContext}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, MCP resources, and ExitPlanMode\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'ExitPlanMode',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n const todoManager = new TodoManager(fileManager, stepLogger);\n\n let planContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const transformedEvents = adapter.transform(message);\n for (const event of transformedEvents) {\n emitEvent(event);\n }\n\n const todoList = await todoManager.checkAndPersistFromMessage(message, task.id);\n if (todoList) {\n emitEvent(adapter.createArtifactEvent('todos', todoList));\n }\n\n // Extract text content for plan\n if (message.type === 'assistant' && message.message?.content) {\n for (const block of message.message.content) {\n if (block.type === 'text' && block.text) {\n planContent += `${block.text}\\n`;\n }\n }\n }\n }\n\n if (planContent.trim()) {\n await fileManager.writePlan(task.id, planContent.trim());\n stepLogger.info('Plan completed', { taskId: task.id });\n }\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Planning phase for ${task.title}`,\n });\n\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'planning' }));\n return { status: 'completed', halt: true };\n }\n\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'planning' }));\n return { status: 'completed' };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -58,9 +58,9 @@ const researchStep = async ({ step, context }) => {
|
|
|
58
58
|
let jsonContent = '';
|
|
59
59
|
for await (const message of response) {
|
|
60
60
|
emitEvent(adapter.createRawSDKEvent(message));
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
emitEvent(
|
|
61
|
+
const transformedEvents = adapter.transform(message);
|
|
62
|
+
for (const event of transformedEvents) {
|
|
63
|
+
emitEvent(event);
|
|
64
64
|
}
|
|
65
65
|
if (message.type === 'assistant' && message.message?.content) {
|
|
66
66
|
for (const c of message.message.content) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"research.js","sources":["../../../../src/workflow/steps/research.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport type { ResearchEvaluation } from '../../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\n\nexport const researchStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('ResearchStep');\n\n const existingResearch = await fileManager.readResearch(task.id);\n if (existingResearch) {\n stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });\n \n // If there are unanswered questions, re-emit them so UI can prompt user\n if (existingResearch.questions && !existingResearch.answered) {\n stepLogger.info('Re-emitting unanswered research questions', { \n taskId: task.id,\n questionCount: existingResearch.questions.length \n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: existingResearch.questions,\n });\n \n // In local mode, halt to allow user to answer\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'skipped', halt: true };\n }\n }\n \n return { status: 'skipped' };\n }\n\n stepLogger.info('Starting research phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));\n\n const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);\n const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\\n\\n${researchPrompt}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, and MCP resources\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n let jsonContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const transformed = adapter.transform(message);\n if (transformed) {\n emitEvent(transformed);\n }\n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) {\n jsonContent += c.text;\n }\n }\n }\n }\n\n if (!jsonContent.trim()) {\n stepLogger.error('No JSON output from research agent', { taskId: task.id });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: 'Research agent returned no output',\n });\n return { status: 'completed', halt: true };\n }\n\n // Parse JSON response\n let evaluation: ResearchEvaluation;\n try {\n // Extract JSON from potential markdown code blocks or other wrapping\n const jsonMatch = jsonContent.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n throw new Error('No JSON object found in response');\n }\n evaluation = JSON.parse(jsonMatch[0]);\n stepLogger.info('Parsed research evaluation', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n } catch (error) {\n stepLogger.error('Failed to parse research JSON', {\n taskId: task.id,\n error: error instanceof Error ? error.message : String(error),\n content: jsonContent.substring(0, 500),\n });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: `Failed to parse research JSON: ${\n error instanceof Error ? error.message : String(error)\n }`,\n });\n return { status: 'completed', halt: true };\n }\n\n // Add answered/answers fields to evaluation\n if (evaluation.questions && evaluation.questions.length > 0) {\n evaluation.answered = false;\n evaluation.answers = undefined;\n }\n\n // Always write research.json\n await fileManager.writeResearch(task.id, evaluation);\n stepLogger.info('Research evaluation written', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n\n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_evaluation',\n content: evaluation,\n });\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Research phase for ${task.title}`,\n });\n\n // Log whether questions need answering\n if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {\n stepLogger.info('Actionability score below threshold, questions needed', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n questionCount: evaluation.questions.length,\n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: evaluation.questions,\n });\n } else {\n stepLogger.info('Actionability score acceptable, proceeding to planning', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n });\n }\n\n // In local mode, always halt after research for user review\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // In cloud mode, check if questions need answering\n const researchData = await fileManager.readResearch(task.id);\n if (researchData?.questions && !researchData.answered) {\n // Questions need answering - halt for user input in cloud mode too\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // No questions or questions already answered - proceed to planning\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed' };\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"research.js","sources":["../../../../src/workflow/steps/research.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport type { ResearchEvaluation } from '../../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\n\nexport const researchStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('ResearchStep');\n\n const existingResearch = await fileManager.readResearch(task.id);\n if (existingResearch) {\n stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });\n \n // If there are unanswered questions, re-emit them so UI can prompt user\n if (existingResearch.questions && !existingResearch.answered) {\n stepLogger.info('Re-emitting unanswered research questions', { \n taskId: task.id,\n questionCount: existingResearch.questions.length \n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: existingResearch.questions,\n });\n \n // In local mode, halt to allow user to answer\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'skipped', halt: true };\n }\n }\n \n return { status: 'skipped' };\n }\n\n stepLogger.info('Starting research phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));\n\n const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);\n const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\\n\\n${researchPrompt}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, and MCP resources\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n let jsonContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const transformedEvents = adapter.transform(message);\n for (const event of transformedEvents) {\n emitEvent(event);\n }\n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) {\n jsonContent += c.text;\n }\n }\n }\n }\n\n if (!jsonContent.trim()) {\n stepLogger.error('No JSON output from research agent', { taskId: task.id });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: 'Research agent returned no output',\n });\n return { status: 'completed', halt: true };\n }\n\n // Parse JSON response\n let evaluation: ResearchEvaluation;\n try {\n // Extract JSON from potential markdown code blocks or other wrapping\n const jsonMatch = jsonContent.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n throw new Error('No JSON object found in response');\n }\n evaluation = JSON.parse(jsonMatch[0]);\n stepLogger.info('Parsed research evaluation', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n } catch (error) {\n stepLogger.error('Failed to parse research JSON', {\n taskId: task.id,\n error: error instanceof Error ? error.message : String(error),\n content: jsonContent.substring(0, 500),\n });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: `Failed to parse research JSON: ${\n error instanceof Error ? error.message : String(error)\n }`,\n });\n return { status: 'completed', halt: true };\n }\n\n // Add answered/answers fields to evaluation\n if (evaluation.questions && evaluation.questions.length > 0) {\n evaluation.answered = false;\n evaluation.answers = undefined;\n }\n\n // Always write research.json\n await fileManager.writeResearch(task.id, evaluation);\n stepLogger.info('Research evaluation written', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n\n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_evaluation',\n content: evaluation,\n });\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Research phase for ${task.title}`,\n });\n\n // Log whether questions need answering\n if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {\n stepLogger.info('Actionability score below threshold, questions needed', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n questionCount: evaluation.questions.length,\n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: evaluation.questions,\n });\n } else {\n stepLogger.info('Actionability score acceptable, proceeding to planning', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n });\n }\n\n // In local mode, always halt after research for user review\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // In cloud mode, check if questions need answering\n const researchData = await fileManager.readResearch(task.id);\n if (researchData?.questions && !researchData.answered) {\n // Questions need answering - halt for user input in cloud mode too\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // No questions or questions already answered - proceed to planning\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed' };\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentEvent } from '../../types.js';
|
|
1
|
+
import type { AgentEvent, ArtifactEvent, StatusEvent } from '../../types.js';
|
|
2
2
|
import type { SDKMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
3
3
|
import type { ProviderAdapter } from '../types.js';
|
|
4
4
|
import { ClaudeToolMapper } from './tool-mapper.js';
|
|
@@ -18,72 +18,71 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
transform(sdkMessage: SDKMessage): AgentEvent
|
|
21
|
+
transform(sdkMessage: SDKMessage): AgentEvent[] {
|
|
22
22
|
const baseEvent = { ts: Date.now() };
|
|
23
23
|
|
|
24
|
-
// Handle stream events
|
|
25
24
|
if (sdkMessage.type === 'stream_event') {
|
|
26
25
|
const event = sdkMessage.event;
|
|
27
26
|
|
|
28
27
|
switch (event.type) {
|
|
29
28
|
case 'message_start':
|
|
30
|
-
return {
|
|
29
|
+
return [{
|
|
31
30
|
...baseEvent,
|
|
32
31
|
type: 'message_start',
|
|
33
32
|
messageId: event.message?.id,
|
|
34
33
|
model: event.message?.model
|
|
35
|
-
};
|
|
34
|
+
}];
|
|
36
35
|
|
|
37
36
|
case 'content_block_start':
|
|
38
37
|
const contentBlock = event.content_block;
|
|
39
|
-
if (!contentBlock) return
|
|
38
|
+
if (!contentBlock) return [];
|
|
40
39
|
|
|
41
|
-
return {
|
|
40
|
+
return [{
|
|
42
41
|
...baseEvent,
|
|
43
42
|
type: 'content_block_start',
|
|
44
43
|
index: event.index,
|
|
45
44
|
contentType: contentBlock.type as 'text' | 'tool_use' | 'thinking',
|
|
46
45
|
toolName: contentBlock.type === 'tool_use' ? contentBlock.name : undefined,
|
|
47
46
|
toolId: contentBlock.type === 'tool_use' ? contentBlock.id : undefined
|
|
48
|
-
};
|
|
47
|
+
}];
|
|
49
48
|
|
|
50
49
|
case 'content_block_delta':
|
|
51
50
|
const delta = event.delta;
|
|
52
|
-
if (!delta) return
|
|
51
|
+
if (!delta) return [];
|
|
53
52
|
|
|
54
53
|
if (delta.type === 'text_delta') {
|
|
55
|
-
return {
|
|
54
|
+
return [{
|
|
56
55
|
...baseEvent,
|
|
57
56
|
type: 'token',
|
|
58
57
|
content: delta.text,
|
|
59
58
|
contentType: 'text'
|
|
60
|
-
};
|
|
59
|
+
}];
|
|
61
60
|
} else if (delta.type === 'input_json_delta') {
|
|
62
|
-
return {
|
|
61
|
+
return [{
|
|
63
62
|
...baseEvent,
|
|
64
63
|
type: 'token',
|
|
65
64
|
content: delta.partial_json,
|
|
66
65
|
contentType: 'tool_input'
|
|
67
|
-
};
|
|
66
|
+
}];
|
|
68
67
|
} else if (delta.type === 'thinking_delta') {
|
|
69
|
-
return {
|
|
68
|
+
return [{
|
|
70
69
|
...baseEvent,
|
|
71
70
|
type: 'token',
|
|
72
71
|
content: delta.thinking,
|
|
73
72
|
contentType: 'thinking'
|
|
74
|
-
};
|
|
73
|
+
}];
|
|
75
74
|
}
|
|
76
|
-
return
|
|
75
|
+
return [];
|
|
77
76
|
|
|
78
77
|
case 'content_block_stop':
|
|
79
|
-
return {
|
|
78
|
+
return [{
|
|
80
79
|
...baseEvent,
|
|
81
80
|
type: 'content_block_stop',
|
|
82
81
|
index: event.index
|
|
83
|
-
};
|
|
82
|
+
}];
|
|
84
83
|
|
|
85
84
|
case 'message_delta':
|
|
86
|
-
return {
|
|
85
|
+
return [{
|
|
87
86
|
...baseEvent,
|
|
88
87
|
type: 'message_delta',
|
|
89
88
|
stopReason: event.delta?.stop_reason,
|
|
@@ -91,20 +90,20 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
91
90
|
usage: event.usage ? {
|
|
92
91
|
outputTokens: event.usage.output_tokens
|
|
93
92
|
} : undefined
|
|
94
|
-
};
|
|
93
|
+
}];
|
|
95
94
|
|
|
96
95
|
case 'message_stop':
|
|
97
|
-
return {
|
|
96
|
+
return [{
|
|
98
97
|
...baseEvent,
|
|
99
98
|
type: 'message_stop'
|
|
100
|
-
};
|
|
99
|
+
}];
|
|
101
100
|
|
|
102
101
|
case 'ping':
|
|
103
102
|
// Ignore ping events
|
|
104
|
-
return
|
|
103
|
+
return [];
|
|
105
104
|
|
|
106
105
|
case 'error':
|
|
107
|
-
return {
|
|
106
|
+
return [{
|
|
108
107
|
...baseEvent,
|
|
109
108
|
type: 'error',
|
|
110
109
|
message: event.error?.message || 'Unknown error',
|
|
@@ -115,18 +114,20 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
115
114
|
code: event.error.code,
|
|
116
115
|
} : undefined,
|
|
117
116
|
sdkError: event.error
|
|
118
|
-
};
|
|
117
|
+
}];
|
|
119
118
|
|
|
120
119
|
default:
|
|
121
|
-
return
|
|
120
|
+
return [];
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
// Handle assistant messages (full message, not streaming)
|
|
126
125
|
if (sdkMessage.type === 'assistant') {
|
|
127
126
|
const message = sdkMessage.message;
|
|
127
|
+
const events: AgentEvent[] = [];
|
|
128
128
|
|
|
129
129
|
// Extract tool calls from content blocks
|
|
130
|
+
// A single assistant message can contain multiple tool_use blocks
|
|
130
131
|
if (message.content && Array.isArray(message.content)) {
|
|
131
132
|
for (const block of message.content) {
|
|
132
133
|
if (block.type === 'tool_use') {
|
|
@@ -139,31 +140,36 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
139
140
|
args: block.input || {},
|
|
140
141
|
parentToolUseId: sdkMessage.parent_tool_use_id
|
|
141
142
|
};
|
|
142
|
-
// Enrich with tool metadata
|
|
143
|
-
|
|
143
|
+
// Enrich with tool metadata and add to events array
|
|
144
|
+
events.push(this.toolMapper.enrichToolCall(toolCallEvent));
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
// If we found tool calls, return them
|
|
150
|
+
if (events.length > 0) {
|
|
151
|
+
return events;
|
|
152
|
+
}
|
|
153
|
+
|
|
148
154
|
// If no tool calls, emit status event
|
|
149
|
-
return {
|
|
155
|
+
return [{
|
|
150
156
|
...baseEvent,
|
|
151
157
|
type: 'status',
|
|
152
158
|
phase: 'assistant_message',
|
|
153
159
|
messageId: message.id,
|
|
154
160
|
model: message.model
|
|
155
|
-
};
|
|
161
|
+
}];
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
// Handle user messages
|
|
159
165
|
if (sdkMessage.type === 'user') {
|
|
160
166
|
const message = sdkMessage.message;
|
|
167
|
+
const events: AgentEvent[] = [];
|
|
161
168
|
|
|
162
|
-
// Check for tool results in content blocks
|
|
163
|
-
if (message?.content && Array.isArray(message.content)) {
|
|
169
|
+
// Check for tool results in content blocks, A single user message can contain multiple tool_result blocks
|
|
170
|
+
if (message?.content && Array.isArray(message.content)) {
|
|
164
171
|
for (const block of message.content) {
|
|
165
172
|
if (block.type === 'tool_result') {
|
|
166
|
-
// Create tool_result event and enrich with metadata
|
|
167
173
|
const toolResultEvent = {
|
|
168
174
|
...baseEvent,
|
|
169
175
|
type: 'tool_result' as const,
|
|
@@ -173,29 +179,33 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
173
179
|
isError: block.is_error,
|
|
174
180
|
parentToolUseId: sdkMessage.parent_tool_use_id
|
|
175
181
|
};
|
|
176
|
-
|
|
177
|
-
return this.toolMapper.enrichToolResult(toolResultEvent);
|
|
182
|
+
events.push(this.toolMapper.enrichToolResult(toolResultEvent));
|
|
178
183
|
}
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
// If we found tool results, return them
|
|
188
|
+
if (events.length > 0) {
|
|
189
|
+
return events;
|
|
190
|
+
}
|
|
191
|
+
|
|
182
192
|
// Otherwise extract text content
|
|
183
193
|
const textContent = this.extractUserContent(message?.content);
|
|
184
194
|
if (!textContent) {
|
|
185
|
-
return
|
|
195
|
+
return [];
|
|
186
196
|
}
|
|
187
|
-
return {
|
|
197
|
+
return [{
|
|
188
198
|
...baseEvent,
|
|
189
199
|
type: 'user_message',
|
|
190
200
|
content: textContent,
|
|
191
201
|
isSynthetic: sdkMessage.isSynthetic
|
|
192
|
-
};
|
|
202
|
+
}];
|
|
193
203
|
}
|
|
194
204
|
|
|
195
205
|
// Handle result messages
|
|
196
206
|
if (sdkMessage.type === 'result') {
|
|
197
207
|
if (sdkMessage.subtype === 'success') {
|
|
198
|
-
return {
|
|
208
|
+
return [{
|
|
199
209
|
...baseEvent,
|
|
200
210
|
type: 'done',
|
|
201
211
|
result: sdkMessage.result,
|
|
@@ -206,9 +216,9 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
206
216
|
usage: sdkMessage.usage,
|
|
207
217
|
modelUsage: sdkMessage.modelUsage,
|
|
208
218
|
permissionDenials: sdkMessage.permission_denials
|
|
209
|
-
};
|
|
219
|
+
}];
|
|
210
220
|
} else {
|
|
211
|
-
return {
|
|
221
|
+
return [{
|
|
212
222
|
...baseEvent,
|
|
213
223
|
type: 'error',
|
|
214
224
|
message: `Execution failed: ${sdkMessage.subtype}`,
|
|
@@ -220,14 +230,14 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
220
230
|
num_turns: sdkMessage.num_turns
|
|
221
231
|
},
|
|
222
232
|
sdkError: sdkMessage
|
|
223
|
-
};
|
|
233
|
+
}];
|
|
224
234
|
}
|
|
225
235
|
}
|
|
226
236
|
|
|
227
237
|
// Handle system messages
|
|
228
238
|
if (sdkMessage.type === 'system') {
|
|
229
239
|
if (sdkMessage.subtype === 'init') {
|
|
230
|
-
return {
|
|
240
|
+
return [{
|
|
231
241
|
...baseEvent,
|
|
232
242
|
type: 'init',
|
|
233
243
|
model: sdkMessage.model,
|
|
@@ -239,21 +249,21 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
239
249
|
slashCommands: sdkMessage.slash_commands,
|
|
240
250
|
outputStyle: sdkMessage.output_style,
|
|
241
251
|
mcpServers: sdkMessage.mcp_servers
|
|
242
|
-
};
|
|
252
|
+
}];
|
|
243
253
|
} else if (sdkMessage.subtype === 'compact_boundary') {
|
|
244
|
-
return {
|
|
254
|
+
return [{
|
|
245
255
|
...baseEvent,
|
|
246
256
|
type: 'compact_boundary',
|
|
247
257
|
trigger: sdkMessage.compact_metadata.trigger,
|
|
248
258
|
preTokens: sdkMessage.compact_metadata.pre_tokens
|
|
249
|
-
};
|
|
259
|
+
}];
|
|
250
260
|
}
|
|
251
261
|
}
|
|
252
262
|
|
|
253
|
-
return
|
|
263
|
+
return [];
|
|
254
264
|
}
|
|
255
265
|
|
|
256
|
-
createStatusEvent(phase: string, additionalData?: any):
|
|
266
|
+
createStatusEvent(phase: string, additionalData?: any): StatusEvent {
|
|
257
267
|
return {
|
|
258
268
|
type: 'status',
|
|
259
269
|
ts: Date.now(),
|
|
@@ -262,6 +272,15 @@ export class ClaudeAdapter implements ProviderAdapter {
|
|
|
262
272
|
};
|
|
263
273
|
}
|
|
264
274
|
|
|
275
|
+
createArtifactEvent(kind: string, content: any): ArtifactEvent {
|
|
276
|
+
return {
|
|
277
|
+
type: 'artifact',
|
|
278
|
+
ts: Date.now(),
|
|
279
|
+
kind,
|
|
280
|
+
content
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
265
284
|
private extractUserContent(content: unknown): string | null {
|
|
266
285
|
if (!content) {
|
|
267
286
|
return null;
|
package/src/adapters/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentEvent, StatusEvent } from '../types.js';
|
|
1
|
+
import type { AgentEvent, StatusEvent, ArtifactEvent } from '../types.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Provider adapter interface for transforming provider-specific messages
|
|
@@ -12,10 +12,10 @@ export interface ProviderAdapter {
|
|
|
12
12
|
name: string;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Transform a provider-specific SDK message into
|
|
16
|
-
* Returns
|
|
15
|
+
* Transform a provider-specific SDK message into one or more AgentEvents.
|
|
16
|
+
* Returns an array of events (can be empty if the message should be ignored).
|
|
17
17
|
*/
|
|
18
|
-
transform(sdkMessage: unknown): AgentEvent
|
|
18
|
+
transform(sdkMessage: unknown): AgentEvent[];
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Create a standardized status event.
|
|
@@ -23,6 +23,12 @@ export interface ProviderAdapter {
|
|
|
23
23
|
*/
|
|
24
24
|
createStatusEvent(phase: string, additionalData?: any): StatusEvent;
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Create an artifact event for custom task artifacts (todos, etc).
|
|
28
|
+
* Used to emit structured artifacts for UI consumption.
|
|
29
|
+
*/
|
|
30
|
+
createArtifactEvent(kind: string, content: any): ArtifactEvent;
|
|
31
|
+
|
|
26
32
|
/**
|
|
27
33
|
* Create a raw SDK event for debugging purposes.
|
|
28
34
|
* Wraps the original SDK message in a raw_sdk_event.
|
package/src/agent.ts
CHANGED
|
@@ -214,10 +214,9 @@ export class Agent {
|
|
|
214
214
|
this.logger.debug('Received message in direct run', message);
|
|
215
215
|
// Emit raw SDK event
|
|
216
216
|
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
this.emitEvent(transformedEvent);
|
|
217
|
+
const transformedEvents = this.adapter.transform(message);
|
|
218
|
+
for (const event of transformedEvents) {
|
|
219
|
+
this.emitEvent(event);
|
|
221
220
|
}
|
|
222
221
|
results.push(message);
|
|
223
222
|
}
|
|
@@ -308,11 +307,16 @@ export class Agent {
|
|
|
308
307
|
return commitHash;
|
|
309
308
|
}
|
|
310
309
|
|
|
311
|
-
async createPullRequest(
|
|
310
|
+
async createPullRequest(
|
|
311
|
+
taskId: string,
|
|
312
|
+
branchName: string,
|
|
313
|
+
taskTitle: string,
|
|
314
|
+
taskDescription: string,
|
|
315
|
+
customBody?: string
|
|
316
|
+
): Promise<string> {
|
|
312
317
|
this.logger.info('Creating pull request', { taskId, branchName, taskTitle });
|
|
313
318
|
|
|
314
|
-
|
|
315
|
-
const prBody = `## Task Details
|
|
319
|
+
const defaultBody = `## Task Details
|
|
316
320
|
**Task ID**: ${taskId}
|
|
317
321
|
**Description**: ${taskDescription}
|
|
318
322
|
|
|
@@ -320,6 +324,7 @@ export class Agent {
|
|
|
320
324
|
This PR implements the changes described in the task.
|
|
321
325
|
|
|
322
326
|
Generated by PostHog Agent`;
|
|
327
|
+
const prBody = customBody || defaultBody;
|
|
323
328
|
|
|
324
329
|
const prUrl = await this.gitManager.createPullRequest(
|
|
325
330
|
branchName,
|
|
@@ -447,11 +452,15 @@ Generated by PostHog Agent`;
|
|
|
447
452
|
}
|
|
448
453
|
|
|
449
454
|
const branchName = await this.gitManager.getCurrentBranch();
|
|
455
|
+
const finalizeResult = stepResults['finalize'];
|
|
456
|
+
const prBody = finalizeResult?.prBody;
|
|
457
|
+
|
|
450
458
|
const prUrl = await this.createPullRequest(
|
|
451
459
|
task.id,
|
|
452
460
|
branchName,
|
|
453
461
|
task.title,
|
|
454
|
-
task.description ?? ''
|
|
462
|
+
task.description ?? '',
|
|
463
|
+
prBody
|
|
455
464
|
);
|
|
456
465
|
|
|
457
466
|
this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
|
package/src/agents/research.ts
CHANGED
|
@@ -19,7 +19,14 @@ Calculate an actionabilityScore (0-1) based on:
|
|
|
19
19
|
|
|
20
20
|
If actionabilityScore < 0.7, generate specific clarifying questions to increase confidence.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Questions must present complete implementation choices, NOT request information from the user:
|
|
23
|
+
options: array of strings
|
|
24
|
+
- GOOD: options: ["Use Redux Toolkit (matches pattern in src/store/)", "Zustand (lighter weight)"]
|
|
25
|
+
- BAD: "Tell me which state management library to use"
|
|
26
|
+
- GOOD: options: ["Place in Button.tsx (existing component)", "create NewButton.tsx (separate concerns)?"]
|
|
27
|
+
- BAD: "Where should I put this code?"
|
|
28
|
+
|
|
29
|
+
DO NOT ask questions like "how should I fix this" or "tell me the pattern" — present concrete options that can be directly chosen and acted upon.
|
|
23
30
|
</objective>
|
|
24
31
|
|
|
25
32
|
<process>
|
|
@@ -60,6 +67,9 @@ Rules:
|
|
|
60
67
|
- questions: ONLY include if actionabilityScore < 0.7
|
|
61
68
|
- Each question must have 2-3 options (maximum 3)
|
|
62
69
|
- Max 3 questions total
|
|
70
|
+
- Options must be complete, actionable choices that require NO additional user input
|
|
71
|
+
- NEVER use options like "Tell me the pattern", "Show me examples", "Specify the approach"
|
|
72
|
+
- Each option must be a full implementation decision that can be directly acted upon
|
|
63
73
|
</output_format>
|
|
64
74
|
|
|
65
75
|
<scoring_examples>
|
|
@@ -92,11 +102,25 @@ Questions needed: What feature? Which product area? What should it do?
|
|
|
92
102
|
"id": "q1",
|
|
93
103
|
"question": "Which caching layer should we use for API responses?",
|
|
94
104
|
"options": [
|
|
95
|
-
"Redis (existing infrastructure, requires setup)",
|
|
96
|
-
"In-memory cache (simpler,
|
|
97
|
-
"
|
|
105
|
+
"Redis with 1-hour TTL (existing infrastructure, requires Redis client setup)",
|
|
106
|
+
"In-memory LRU cache with 100MB limit (simpler, single-server only)",
|
|
107
|
+
"HTTP Cache-Control headers only (minimal backend changes, relies on browser/CDN)"
|
|
98
108
|
]
|
|
99
109
|
}
|
|
110
|
+
Reason: Each option is a complete, actionable decision with concrete details
|
|
111
|
+
</good_example>
|
|
112
|
+
|
|
113
|
+
<good_example>
|
|
114
|
+
{
|
|
115
|
+
"id": "q2",
|
|
116
|
+
"question": "Where should the new analytics tracking code be placed?",
|
|
117
|
+
"options": [
|
|
118
|
+
"In the existing UserAnalytics.ts module alongside page view tracking",
|
|
119
|
+
"Create a new EventTracking.ts module in src/analytics/ for all event tracking",
|
|
120
|
+
"Add directly to each component that needs tracking (no centralized module)"
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
Reason: Specific file paths and architectural patterns, no user input needed
|
|
100
124
|
</good_example>
|
|
101
125
|
|
|
102
126
|
<bad_example>
|
|
@@ -105,7 +129,33 @@ Questions needed: What feature? Which product area? What should it do?
|
|
|
105
129
|
"question": "How should I implement this?",
|
|
106
130
|
"options": ["One way", "Another way"]
|
|
107
131
|
}
|
|
108
|
-
Reason: Too vague, doesn't explain the tradeoffs
|
|
132
|
+
Reason: Too vague, doesn't explain the tradeoffs or provide concrete details
|
|
133
|
+
</bad_example>
|
|
134
|
+
|
|
135
|
+
<bad_example>
|
|
136
|
+
{
|
|
137
|
+
"id": "q2",
|
|
138
|
+
"question": "Which pattern should we follow for state management?",
|
|
139
|
+
"options": [
|
|
140
|
+
"Tell me which pattern the codebase currently uses",
|
|
141
|
+
"Show me examples of state management",
|
|
142
|
+
"Whatever you think is best"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
Reason: Options request user input instead of being actionable choices. Should be concrete patterns like "Zustand stores (matching existing patterns in src/stores/)" or "React Context (simpler, no new dependencies)"
|
|
146
|
+
</bad_example>
|
|
147
|
+
|
|
148
|
+
<bad_example>
|
|
149
|
+
{
|
|
150
|
+
"id": "q3",
|
|
151
|
+
"question": "What color scheme should the button use?",
|
|
152
|
+
"options": [
|
|
153
|
+
"Use the existing theme colors",
|
|
154
|
+
"Let me specify custom colors",
|
|
155
|
+
"Match the design system"
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
Reason: "Let me specify" requires user input. Should be "Primary blue (#0066FF, existing theme)" or "Secondary gray (#6B7280, existing theme)"
|
|
109
159
|
</bad_example>
|
|
110
160
|
</question_examples>`;
|
|
111
161
|
|