@posthog/agent 1.16.6 → 1.17.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.
Files changed (215) hide show
  1. package/dist/index.d.ts +1 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/src/agent.d.ts +0 -3
  4. package/dist/src/agent.d.ts.map +1 -1
  5. package/dist/src/agent.js +6 -27
  6. package/dist/src/agent.js.map +1 -1
  7. package/dist/src/agents/research.d.ts +1 -1
  8. package/dist/src/agents/research.d.ts.map +1 -1
  9. package/dist/src/agents/research.js +84 -53
  10. package/dist/src/agents/research.js.map +1 -1
  11. package/dist/src/file-manager.d.ts +3 -21
  12. package/dist/src/file-manager.d.ts.map +1 -1
  13. package/dist/src/file-manager.js +15 -47
  14. package/dist/src/file-manager.js.map +1 -1
  15. package/dist/src/git-manager.d.ts.map +1 -1
  16. package/dist/src/git-manager.js +8 -1
  17. package/dist/src/git-manager.js.map +1 -1
  18. package/dist/src/types.d.ts +20 -1
  19. package/dist/src/types.d.ts.map +1 -1
  20. package/dist/src/types.js.map +1 -1
  21. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  22. package/dist/src/workflow/steps/plan.js +26 -18
  23. package/dist/src/workflow/steps/plan.js.map +1 -1
  24. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  25. package/dist/src/workflow/steps/research.js +100 -66
  26. package/dist/src/workflow/steps/research.js.map +1 -1
  27. package/dist/src/workflow/types.d.ts +0 -2
  28. package/dist/src/workflow/types.d.ts.map +1 -1
  29. package/dist/templates/plan-template.md +1 -5
  30. package/package.json +2 -6
  31. package/src/agent.ts +7 -31
  32. package/src/agents/research.ts +84 -53
  33. package/src/file-manager.ts +18 -73
  34. package/src/git-manager.ts +7 -1
  35. package/src/templates/plan-template.md +1 -5
  36. package/src/types.ts +24 -1
  37. package/src/workflow/steps/plan.ts +28 -21
  38. package/src/workflow/steps/research.ts +109 -74
  39. package/src/workflow/types.ts +0 -2
  40. package/dist/_virtual/_commonjsHelpers.js +0 -6
  41. package/dist/_virtual/_commonjsHelpers.js.map +0 -1
  42. package/dist/_virtual/index.js +0 -4
  43. package/dist/_virtual/index.js.map +0 -1
  44. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +0 -1154
  45. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +0 -1
  46. package/dist/node_modules/@ai-sdk/provider/dist/index.js +0 -296
  47. package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +0 -1
  48. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +0 -576
  49. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +0 -1
  50. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +0 -741
  51. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +0 -1
  52. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +0 -112
  53. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +0 -1
  54. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +0 -123
  55. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +0 -1
  56. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +0 -62
  57. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +0 -1
  58. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +0 -91
  59. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +0 -1
  60. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +0 -79
  61. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +0 -1
  62. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +0 -59
  63. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +0 -1
  64. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +0 -99
  65. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +0 -1
  66. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +0 -31
  67. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +0 -1
  68. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +0 -69
  69. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +0 -1
  70. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +0 -54
  71. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +0 -1
  72. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +0 -22
  73. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +0 -1
  74. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +0 -104
  75. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +0 -1
  76. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +0 -44
  77. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +0 -1
  78. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +0 -43
  79. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +0 -1
  80. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +0 -27
  81. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +0 -1
  82. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +0 -62
  83. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +0 -1
  84. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +0 -121
  85. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +0 -1
  86. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +0 -167
  87. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +0 -1
  88. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +0 -33
  89. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +0 -1
  90. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +0 -22
  91. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +0 -1
  92. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +0 -21
  93. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +0 -1
  94. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +0 -35
  95. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +0 -1
  96. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +0 -40
  97. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +0 -1
  98. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +0 -22
  99. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +0 -1
  100. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +0 -70
  101. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +0 -1
  102. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +0 -78
  103. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +0 -1
  104. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +0 -34
  105. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +0 -1
  106. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +0 -55
  107. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +0 -1
  108. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +0 -56
  109. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +0 -1
  110. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +0 -76
  111. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +0 -1
  112. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +0 -27
  113. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +0 -1
  114. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +0 -45
  115. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +0 -1
  116. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +0 -22
  117. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +0 -1
  118. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +0 -25
  119. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +0 -1
  120. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +0 -24
  121. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +0 -1
  122. package/dist/node_modules/@opentelemetry/api/build/esm/version.js +0 -20
  123. package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +0 -1
  124. package/dist/node_modules/ai/dist/index.js +0 -2870
  125. package/dist/node_modules/ai/dist/index.js.map +0 -1
  126. package/dist/node_modules/nanoid/non-secure/index.js +0 -13
  127. package/dist/node_modules/nanoid/non-secure/index.js.map +0 -1
  128. package/dist/node_modules/secure-json-parse/index.js +0 -133
  129. package/dist/node_modules/secure-json-parse/index.js.map +0 -1
  130. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +0 -37
  131. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +0 -1
  132. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +0 -26
  133. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +0 -1
  134. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +0 -17
  135. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +0 -1
  136. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +0 -11
  137. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +0 -1
  138. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +0 -8
  139. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +0 -1
  140. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +0 -66
  141. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +0 -1
  142. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +0 -21
  143. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +0 -1
  144. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +0 -30
  145. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +0 -1
  146. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +0 -53
  147. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +0 -1
  148. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +0 -8
  149. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +0 -1
  150. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +0 -8
  151. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +0 -1
  152. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +0 -8
  153. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +0 -1
  154. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +0 -50
  155. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +0 -1
  156. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +0 -11
  157. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +0 -1
  158. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +0 -11
  159. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +0 -1
  160. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +0 -9
  161. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +0 -1
  162. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +0 -56
  163. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +0 -1
  164. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +0 -24
  165. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +0 -1
  166. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +0 -30
  167. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +0 -1
  168. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +0 -19
  169. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +0 -1
  170. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +0 -15
  171. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +0 -1
  172. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +0 -13
  173. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +0 -1
  174. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +0 -37
  175. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +0 -1
  176. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +0 -56
  177. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +0 -1
  178. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +0 -76
  179. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +0 -1
  180. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +0 -25
  181. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +0 -1
  182. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +0 -24
  183. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +0 -1
  184. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +0 -8
  185. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +0 -1
  186. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +0 -8
  187. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +0 -1
  188. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +0 -65
  189. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +0 -1
  190. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +0 -24
  191. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +0 -1
  192. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +0 -350
  193. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +0 -1
  194. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +0 -36
  195. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +0 -1
  196. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +0 -10
  197. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +0 -1
  198. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +0 -84
  199. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +0 -1
  200. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +0 -8
  201. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +0 -1
  202. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +0 -110
  203. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +0 -1
  204. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +0 -90
  205. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +0 -1
  206. package/dist/src/structured-extraction.d.ts +0 -28
  207. package/dist/src/structured-extraction.d.ts.map +0 -1
  208. package/dist/src/structured-extraction.js +0 -77
  209. package/dist/src/structured-extraction.js.map +0 -1
  210. package/dist/src/utils/ai-sdk.d.ts +0 -14
  211. package/dist/src/utils/ai-sdk.d.ts.map +0 -1
  212. package/dist/src/utils/ai-sdk.js +0 -38
  213. package/dist/src/utils/ai-sdk.js.map +0 -1
  214. package/src/structured-extraction.ts +0 -117
  215. package/src/utils/ai-sdk.ts +0 -47
@@ -3,11 +3,29 @@ import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
3
3
  import { finalizeStepGitActions } from '../utils.js';
4
4
 
5
5
  const researchStep = async ({ step, context }) => {
6
- const { task, cwd, isCloudMode, options, logger, fileManager, gitManager, promptBuilder, adapter, mcpServers, extractor, emitEvent, } = context;
6
+ const { task, cwd, isCloudMode, options, logger, fileManager, gitManager, promptBuilder, adapter, mcpServers, emitEvent, } = context;
7
7
  const stepLogger = logger.child('ResearchStep');
8
8
  const existingResearch = await fileManager.readResearch(task.id);
9
9
  if (existingResearch) {
10
- stepLogger.info('Research already exists, skipping step', { taskId: task.id });
10
+ stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });
11
+ // If there are unanswered questions, re-emit them so UI can prompt user
12
+ if (existingResearch.questions && !existingResearch.answered) {
13
+ stepLogger.info('Re-emitting unanswered research questions', {
14
+ taskId: task.id,
15
+ questionCount: existingResearch.questions.length
16
+ });
17
+ emitEvent({
18
+ type: 'artifact',
19
+ ts: Date.now(),
20
+ kind: 'research_questions',
21
+ content: existingResearch.questions,
22
+ });
23
+ // In local mode, halt to allow user to answer
24
+ if (!isCloudMode) {
25
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
26
+ return { status: 'skipped', halt: true };
27
+ }
28
+ }
11
29
  return { status: 'skipped' };
12
30
  }
13
31
  stepLogger.info('Starting research phase', { taskId: task.id });
@@ -37,7 +55,7 @@ const researchStep = async ({ step, context }) => {
37
55
  prompt: fullPrompt,
38
56
  options: { ...baseOptions, ...(options.queryOverrides || {}) },
39
57
  });
40
- let researchContent = '';
58
+ let jsonContent = '';
41
59
  for await (const message of response) {
42
60
  emitEvent(adapter.createRawSDKEvent(message));
43
61
  const transformed = adapter.transform(message);
@@ -47,87 +65,103 @@ const researchStep = async ({ step, context }) => {
47
65
  if (message.type === 'assistant' && message.message?.content) {
48
66
  for (const c of message.message.content) {
49
67
  if (c.type === 'text' && c.text) {
50
- researchContent += `${c.text}\n`;
68
+ jsonContent += c.text;
51
69
  }
52
70
  }
53
71
  }
54
72
  }
55
- if (researchContent.trim()) {
56
- await fileManager.writeResearch(task.id, researchContent.trim());
57
- stepLogger.info('Research completed', { taskId: task.id });
73
+ if (!jsonContent.trim()) {
74
+ stepLogger.error('No JSON output from research agent', { taskId: task.id });
75
+ emitEvent({
76
+ type: 'error',
77
+ ts: Date.now(),
78
+ message: 'Research agent returned no output',
79
+ });
80
+ return { status: 'completed', halt: true };
81
+ }
82
+ // Parse JSON response
83
+ let evaluation;
84
+ try {
85
+ // Extract JSON from potential markdown code blocks or other wrapping
86
+ const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
87
+ if (!jsonMatch) {
88
+ throw new Error('No JSON object found in response');
89
+ }
90
+ evaluation = JSON.parse(jsonMatch[0]);
91
+ stepLogger.info('Parsed research evaluation', {
92
+ taskId: task.id,
93
+ score: evaluation.actionabilityScore,
94
+ hasQuestions: !!evaluation.questions,
95
+ });
96
+ }
97
+ catch (error) {
98
+ stepLogger.error('Failed to parse research JSON', {
99
+ taskId: task.id,
100
+ error: error instanceof Error ? error.message : String(error),
101
+ content: jsonContent.substring(0, 500),
102
+ });
103
+ emitEvent({
104
+ type: 'error',
105
+ ts: Date.now(),
106
+ message: `Failed to parse research JSON: ${error instanceof Error ? error.message : String(error)}`,
107
+ });
108
+ return { status: 'completed', halt: true };
109
+ }
110
+ // Add answered/answers fields to evaluation
111
+ if (evaluation.questions && evaluation.questions.length > 0) {
112
+ evaluation.answered = false;
113
+ evaluation.answers = undefined;
58
114
  }
115
+ // Always write research.json
116
+ await fileManager.writeResearch(task.id, evaluation);
117
+ stepLogger.info('Research evaluation written', {
118
+ taskId: task.id,
119
+ score: evaluation.actionabilityScore,
120
+ hasQuestions: !!evaluation.questions,
121
+ });
122
+ emitEvent({
123
+ type: 'artifact',
124
+ ts: Date.now(),
125
+ kind: 'research_evaluation',
126
+ content: evaluation,
127
+ });
59
128
  await gitManager.addAllPostHogFiles();
60
129
  await finalizeStepGitActions(context, step, {
61
130
  commitMessage: `Research phase for ${task.title}`,
62
131
  });
63
- if (extractor && researchContent.trim()) {
64
- try {
65
- stepLogger.info('Extracting questions from research.md', { taskId: task.id });
66
- const parsedQuestions = await extractor.extractQuestions(researchContent);
67
- await fileManager.writeQuestions(task.id, {
68
- questions: parsedQuestions,
69
- answered: false,
70
- answers: null,
71
- });
72
- emitEvent({
73
- type: 'artifact',
74
- ts: Date.now(),
75
- kind: 'research_questions',
76
- content: parsedQuestions,
77
- });
78
- stepLogger.info('Questions extracted successfully', {
79
- taskId: task.id,
80
- count: parsedQuestions.length,
81
- });
82
- }
83
- catch (error) {
84
- stepLogger.error('Failed to extract questions', {
85
- taskId: task.id,
86
- error: error instanceof Error ? error.message : String(error),
87
- });
88
- emitEvent({
89
- type: 'error',
90
- ts: Date.now(),
91
- message: `Failed to extract questions: ${error instanceof Error ? error.message : String(error)}`,
92
- });
93
- }
94
- }
95
- else if (!extractor) {
96
- stepLogger.warn('Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.');
132
+ // Log whether questions need answering
133
+ if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {
134
+ stepLogger.info('Actionability score below threshold, questions needed', {
135
+ taskId: task.id,
136
+ score: evaluation.actionabilityScore,
137
+ questionCount: evaluation.questions.length,
138
+ });
97
139
  emitEvent({
98
- type: 'status',
140
+ type: 'artifact',
99
141
  ts: Date.now(),
100
- phase: 'extraction_skipped',
101
- message: 'Question extraction skipped - extractor not configured',
142
+ kind: 'research_questions',
143
+ content: evaluation.questions,
102
144
  });
103
145
  }
146
+ else {
147
+ stepLogger.info('Actionability score acceptable, proceeding to planning', {
148
+ taskId: task.id,
149
+ score: evaluation.actionabilityScore,
150
+ });
151
+ }
152
+ // In local mode, always halt after research for user review
104
153
  if (!isCloudMode) {
105
154
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
106
155
  return { status: 'completed', halt: true };
107
156
  }
108
- const questionsData = await fileManager.readQuestions(task.id);
109
- if (questionsData && !questionsData.answered && extractor && researchContent.trim()) {
110
- const researchQuestions = await extractor.extractQuestionsWithAnswers(researchContent);
111
- const answers = researchQuestions.map((qa) => ({
112
- questionId: qa.id,
113
- selectedOption: qa.recommendedAnswer,
114
- customInput: qa.justification,
115
- }));
116
- await fileManager.writeQuestions(task.id, {
117
- questions: researchQuestions.map((qa) => ({
118
- id: qa.id,
119
- question: qa.question,
120
- options: qa.options,
121
- })),
122
- answered: true,
123
- answers,
124
- });
125
- await gitManager.addAllPostHogFiles();
126
- await finalizeStepGitActions(context, step, {
127
- commitMessage: `Answer research questions for ${task.title}`,
128
- });
129
- stepLogger.info('Auto-answered research questions', { taskId: task.id });
157
+ // In cloud mode, check if questions need answering
158
+ const researchData = await fileManager.readResearch(task.id);
159
+ if (researchData?.questions && !researchData.answered) {
160
+ // Questions need answering - halt for user input in cloud mode too
161
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
162
+ return { status: 'completed', halt: true };
130
163
  }
164
+ // No questions or questions already answered - proceed to planning
131
165
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
132
166
  return { status: 'completed' };
133
167
  };
@@ -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 { ExtractedQuestionWithAnswer } from '../../structured-extraction.js';\nimport type { WorkflowStepRunner } 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 extractor,\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, skipping step', { taskId: task.id });\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 researchContent = '';\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 researchContent += `${c.text}\\n`;\n }\n }\n }\n }\n\n if (researchContent.trim()) {\n await fileManager.writeResearch(task.id, researchContent.trim());\n stepLogger.info('Research completed', { taskId: task.id });\n }\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Research phase for ${task.title}`,\n });\n\n if (extractor && researchContent.trim()) {\n try {\n stepLogger.info('Extracting questions from research.md', { taskId: task.id });\n const parsedQuestions = await extractor.extractQuestions(researchContent);\n\n await fileManager.writeQuestions(task.id, {\n questions: parsedQuestions,\n answered: false,\n answers: null,\n });\n\n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: parsedQuestions,\n });\n\n stepLogger.info('Questions extracted successfully', {\n taskId: task.id,\n count: parsedQuestions.length,\n });\n } catch (error) {\n stepLogger.error('Failed to extract questions', {\n taskId: task.id,\n error: error instanceof Error ? error.message : String(error),\n });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: `Failed to extract questions: ${\n error instanceof Error ? error.message : String(error)\n }`,\n });\n }\n } else if (!extractor) {\n stepLogger.warn(\n 'Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.'\n );\n emitEvent({\n type: 'status',\n ts: Date.now(),\n phase: 'extraction_skipped',\n message: 'Question extraction skipped - extractor not configured',\n });\n }\n\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n const questionsData = await fileManager.readQuestions(task.id);\n if (questionsData && !questionsData.answered && extractor && researchContent.trim()) {\n const researchQuestions = await extractor.extractQuestionsWithAnswers(researchContent);\n const answers = (researchQuestions as ExtractedQuestionWithAnswer[]).map((qa) => ({\n questionId: qa.id,\n selectedOption: qa.recommendedAnswer,\n customInput: qa.justification,\n }));\n\n await fileManager.writeQuestions(task.id, {\n questions: researchQuestions.map((qa) => ({\n id: qa.id,\n question: qa.question,\n options: qa.options,\n })),\n answered: true,\n answers,\n });\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Answer research questions for ${task.title}`,\n });\n stepLogger.info('Auto-answered research questions', { taskId: task.id });\n }\n\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 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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"}
@@ -6,7 +6,6 @@ import type { PromptBuilder } from '../prompt-builder.js';
6
6
  import type { TaskProgressReporter } from '../task-progress-reporter.js';
7
7
  import type { ProviderAdapter } from '../adapters/types.js';
8
8
  import type { PostHogAPIClient } from '../posthog-api.js';
9
- import type { StructuredExtractor } from '../structured-extraction.js';
10
9
  export interface WorkflowRuntime {
11
10
  task: Task;
12
11
  taskSlug: string;
@@ -21,7 +20,6 @@ export interface WorkflowRuntime {
21
20
  adapter: ProviderAdapter;
22
21
  mcpServers?: Record<string, any>;
23
22
  posthogAPI?: PostHogAPIClient;
24
- extractor?: StructuredExtractor;
25
23
  emitEvent: (event: any) => void;
26
24
  stepResults: Record<string, any>;
27
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflow/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE/F,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflow/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE/F,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,EAAE,CAAC"}
@@ -38,8 +38,4 @@ path/to/existing/file.ts - Changes needed
38
38
 
39
39
  - Key architectural decisions
40
40
  - Potential risks and mitigation
41
- - Testing approach
42
-
43
- ---
44
-
45
- *Generated by PostHog Agent*
41
+ - Testing approach
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/agent",
3
- "version": "1.16.6",
3
+ "version": "1.17.0",
4
4
  "description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -49,12 +49,8 @@
49
49
  "typescript": "^5.5.0"
50
50
  },
51
51
  "dependencies": {
52
- "@ai-sdk/anthropic": "^1.0.6",
53
- "@ai-sdk/openai": "^1.0.10",
54
52
  "@anthropic-ai/claude-agent-sdk": "^0.1.1",
55
- "ai": "^4.2.0",
56
- "dotenv": "^17.2.3",
57
- "zod": "^3.24.1"
53
+ "dotenv": "^17.2.3"
58
54
  },
59
55
  "files": [
60
56
  "dist/**/*",
package/src/agent.ts CHANGED
@@ -10,7 +10,6 @@ import type { ProviderAdapter } from './adapters/types.js';
10
10
  import { Logger } from './utils/logger.js';
11
11
  import { PromptBuilder } from './prompt-builder.js';
12
12
  import { TaskProgressReporter } from './task-progress-reporter.js';
13
- import { AISDKExtractor, type StructuredExtractor, type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
14
13
  import { TASK_WORKFLOW } from './workflow/config.js';
15
14
  import type { WorkflowRuntime } from './workflow/types.js';
16
15
 
@@ -26,7 +25,6 @@ export class Agent {
26
25
  private logger: Logger;
27
26
  private progressReporter: TaskProgressReporter;
28
27
  private promptBuilder: PromptBuilder;
29
- private extractor?: StructuredExtractor;
30
28
  private mcpServers?: Record<string, any>;
31
29
  private canUseTool?: CanUseTool;
32
30
  public debug: boolean;
@@ -92,7 +90,6 @@ export class Agent {
92
90
  logger: this.logger.child('PromptBuilder')
93
91
  });
94
92
  this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
95
- this.extractor = new AISDKExtractor({apiKey: config.posthogApiKey, gatewayUrl: this.posthogAPI?.getLlmGatewayUrl() ?? '', logger: this.logger.child('AISDKExtractor')});
96
93
  }
97
94
 
98
95
  /**
@@ -159,7 +156,6 @@ export class Agent {
159
156
  adapter: this.adapter,
160
157
  mcpServers: this.mcpServers,
161
158
  posthogAPI: this.posthogAPI,
162
- extractor: this.extractor,
163
159
  emitEvent: (event: any) => this.emitEvent(event),
164
160
  stepResults: {},
165
161
  };
@@ -283,32 +279,11 @@ export class Agent {
283
279
  return await this.fileManager.readPlan(taskId);
284
280
  }
285
281
 
286
- async extractQuestionsFromResearch(taskId: string, includeAnswers: boolean = false): Promise<ExtractedQuestion[] | ExtractedQuestionWithAnswer[]> {
287
- this.logger.info('Extracting questions from research.md', { taskId, includeAnswers });
288
-
289
- if (!this.extractor) {
290
- throw new Error('OpenAI extractor not initialized. Ensure the LLM gateway is configured.');
291
- }
292
-
293
- const researchContent = await this.fileManager.readResearch(taskId);
294
- if (!researchContent) {
295
- throw new Error('research.md not found for task ' + taskId);
296
- }
297
-
298
- if (includeAnswers) {
299
- return await this.extractor.extractQuestionsWithAnswers(researchContent);
300
- } else {
301
- return await this.extractor.extractQuestions(researchContent);
302
- }
303
- }
304
-
305
282
  // Git operations for task execution
306
283
  async createPlanningBranch(taskId: string): Promise<string> {
307
284
  this.logger.info('Creating planning branch', { taskId });
308
285
  const branchName = await this.gitManager.createTaskPlanningBranch(taskId);
309
286
  this.logger.debug('Planning branch created', { taskId, branchName });
310
- // Only create gitignore after we're on the new branch
311
- await this.fileManager.ensureGitignore();
312
287
  return branchName;
313
288
  }
314
289
 
@@ -422,12 +397,17 @@ Generated by PostHog Agent`;
422
397
  const branchName = await this.gitManager.createTaskBranch(taskSlug);
423
398
  this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
424
399
 
425
- await this.fileManager.ensureGitignore();
426
400
  await this.gitManager.addAllPostHogFiles();
401
+
402
+ // Only commit if there are changes or we're in cloud mode
427
403
  if (isCloudMode) {
428
404
  await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
429
405
  } else {
430
- await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
406
+ // Check if there are any changes before committing
407
+ const hasChanges = await this.gitManager.hasStagedChanges();
408
+ if (hasChanges) {
409
+ await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
410
+ }
431
411
  }
432
412
  } else {
433
413
  this.logger.info('Switching to existing task branch', { branch: existingBranch });
@@ -446,10 +426,6 @@ Generated by PostHog Agent`;
446
426
  if (resolvedToken) {
447
427
  process.env.OPENAI_API_KEY = resolvedToken;
448
428
  }
449
-
450
- if (!this.extractor) {
451
- this.extractor = new AISDKExtractor({apiKey: resolvedToken || '', gatewayUrl: resolvedGatewayUrl || '', logger: this.logger.child('AISDKExtractor')});
452
- }
453
429
  }
454
430
 
455
431
  private async ensurePullRequest(task: Task, stepResults: Record<string, any>): Promise<void> {
@@ -1,80 +1,111 @@
1
1
  export const RESEARCH_SYSTEM_PROMPT = `<role>
2
- PostHog AI Research Agent — analyze codebases to understand implementation context and identify areas of focus for development tasks.
2
+ PostHog AI Research Agent — analyze codebases to evaluate task actionability and identify missing information.
3
3
  </role>
4
4
 
5
5
  <constraints>
6
6
  - Read-only: analyze files, search code, explore structure
7
7
  - No modifications or code changes
8
+ - Output structured JSON only
8
9
  </constraints>
9
10
 
10
11
  <objective>
11
- Your PRIMARY goal is to understand the codebase thoroughly and provide context for the planning phase.
12
+ Your PRIMARY goal is to evaluate whether a task is actionable and assign an actionability score.
12
13
 
13
- ONLY generate clarifying questions if:
14
- - The task description is genuinely vague or ambiguous
15
- - There are multiple valid architectural approaches with significant tradeoffs
16
- - Critical information is missing that cannot be inferred from the codebase
14
+ Calculate an actionabilityScore (0-1) based on:
15
+ - **Task clarity** (0.4 weight): Is the task description specific and unambiguous?
16
+ - **Codebase context** (0.3 weight): Can you locate the relevant code and patterns?
17
+ - **Architectural decisions** (0.2 weight): Are the implementation approaches clear?
18
+ - **Dependencies** (0.1 weight): Are required dependencies and constraints understood?
17
19
 
18
- DO NOT ask questions like "how should I fix this" or "what approach do you prefer" — that defeats the purpose of autonomous task execution. The user has already specified what they want done.
20
+ If actionabilityScore < 0.7, generate specific clarifying questions to increase confidence.
21
+
22
+ DO NOT ask questions like "how should I fix this" — focus on missing information that prevents confident planning.
19
23
  </objective>
20
24
 
21
25
  <process>
22
26
  1. Explore repository structure and identify relevant files/components
23
27
  2. Understand existing patterns, conventions, and dependencies
24
- 3. Locate similar implementations or related code
25
- 4. Identify the key areas of the codebase that will be affected
26
- 5. Document your findings to provide context for planning
27
- 6. ONLY if genuinely needed: generate 2-3 specific clarification questions
28
+ 3. Calculate actionabilityScore based on clarity, context, architecture, and dependencies
29
+ 4. Identify key files that will need modification
30
+ 5. If score < 0.7: generate 2-4 specific questions to resolve blockers
31
+ 6. Output JSON matching ResearchEvaluation schema
28
32
  </process>
29
33
 
30
34
  <output_format>
31
- Output ONLY the markdown artifact with no preamble:
32
-
33
- \`\`\`markdown
34
- # Research Findings
35
-
36
- ## Codebase Analysis
37
- [Brief summary of relevant code structure, patterns, and files]
38
-
39
- ## Key Areas of Focus
40
- [List specific files/components that need modification]
41
-
42
- ## Implementation Context
43
- [Important patterns, dependencies, or constraints found in the code]
44
-
45
- ## Clarifying Questions
46
- [ONLY include this section if it will increase the quality of the plan]
47
-
48
- ## Question 1: [Specific architectural decision]
49
- **Options:**
50
- - a) [Concrete option with file references]
51
- - b) [Alternative with file references]
52
- - c) Something else (please specify)
53
- \`\`\`
54
-
55
- Format requirements:
56
- - Use "## Question N:" for question headers (h2)
57
- - Follow with "**Options:**" on its own line
58
- - Start options with "- a)", "- b)", "- c)"
59
- - Always include "c) Something else (please specify)"
60
- - Max 4 questions total
35
+ Output ONLY valid JSON with no markdown wrappers, no preamble, no explanation:
36
+
37
+ {
38
+ "actionabilityScore": 0.85,
39
+ "context": "Brief 2-3 sentence summary of the task and implementation approach",
40
+ "keyFiles": ["path/to/file1.ts", "path/to/file2.ts"],
41
+ "blockers": ["Optional: what's preventing full confidence"],
42
+ "questions": [
43
+ {
44
+ "id": "q1",
45
+ "question": "Specific architectural decision needed?",
46
+ "options": [
47
+ "First approach with concrete details",
48
+ "Alternative approach with concrete details",
49
+ "Third option if needed"
50
+ ]
51
+ }
52
+ ]
53
+ }
54
+
55
+ Rules:
56
+ - actionabilityScore: number between 0 and 1
57
+ - context: concise summary for planning phase
58
+ - keyFiles: array of file paths that need modification
59
+ - blockers: optional array explaining confidence gaps
60
+ - questions: ONLY include if actionabilityScore < 0.7
61
+ - Each question must have 2-3 options (maximum 3)
62
+ - Max 3 questions total
61
63
  </output_format>
62
64
 
63
- <examples>
65
+ <scoring_examples>
66
+ <example score="0.9">
67
+ Task: "Fix typo in login button text"
68
+ Reasoning: Completely clear task, found exact component, no architectural decisions
69
+ </example>
70
+
71
+ <example score="0.75">
72
+ Task: "Add caching to API endpoints"
73
+ Reasoning: Clear goal, found endpoints, but multiple caching strategies possible
74
+ </example>
75
+
76
+ <example score="0.55">
77
+ Task: "Improve performance"
78
+ Reasoning: Vague task, unclear scope, needs questions about which areas to optimize
79
+ Questions needed: Which features are slow? What metrics define success?
80
+ </example>
81
+
82
+ <example score="0.3">
83
+ Task: "Add the new feature"
84
+ Reasoning: Extremely vague, no context, cannot locate relevant code
85
+ Questions needed: What feature? Which product area? What should it do?
86
+ </example>
87
+ </scoring_examples>
88
+
89
+ <question_examples>
64
90
  <good_example>
65
- Task: "Fix authentication bug in login flow"
66
- Output: Research findings showing auth flow files, patterns used, NO questions needed
91
+ {
92
+ "id": "q1",
93
+ "question": "Which caching layer should we use for API responses?",
94
+ "options": [
95
+ "Redis (existing infrastructure, requires setup)",
96
+ "In-memory cache (simpler, but not distributed)",
97
+ "Browser-side caching only (minimal backend changes)"
98
+ ]
99
+ }
67
100
  </good_example>
68
101
 
69
102
  <bad_example>
70
- Task: "Fix authentication bug"
71
- Output: "How should I fix the authentication? a) Fix it one way b) Fix it another way"
72
- Reason: Don't ask HOW to do the task — that's what the agent is for
103
+ {
104
+ "id": "q1",
105
+ "question": "How should I implement this?",
106
+ "options": ["One way", "Another way"]
107
+ }
108
+ Reason: Too vague, doesn't explain the tradeoffs
73
109
  </bad_example>
74
-
75
- <good_example>
76
- Task: "Add caching to API endpoints"
77
- Output: Research showing existing cache implementations, question about cache backend choice IF multiple production systems are already in use
78
- </good_example>
79
- </examples>`;
110
+ </question_examples>`;
80
111