@posthog/agent 1.16.6 → 1.18.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 (227) hide show
  1. package/README.md +6 -2
  2. package/dist/claude-cli/cli.js +3617 -0
  3. package/dist/claude-cli/package.json +3 -0
  4. package/dist/index.d.ts +1 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/src/agent.d.ts +0 -3
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +6 -27
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/agents/research.d.ts +1 -1
  11. package/dist/src/agents/research.d.ts.map +1 -1
  12. package/dist/src/agents/research.js +84 -53
  13. package/dist/src/agents/research.js.map +1 -1
  14. package/dist/src/file-manager.d.ts +3 -21
  15. package/dist/src/file-manager.d.ts.map +1 -1
  16. package/dist/src/file-manager.js +15 -47
  17. package/dist/src/file-manager.js.map +1 -1
  18. package/dist/src/git-manager.d.ts.map +1 -1
  19. package/dist/src/git-manager.js +8 -1
  20. package/dist/src/git-manager.js.map +1 -1
  21. package/dist/src/posthog-api.d.ts +6 -1
  22. package/dist/src/posthog-api.d.ts.map +1 -1
  23. package/dist/src/posthog-api.js +28 -0
  24. package/dist/src/posthog-api.js.map +1 -1
  25. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  26. package/dist/src/task-progress-reporter.js +0 -1
  27. package/dist/src/task-progress-reporter.js.map +1 -1
  28. package/dist/src/types.d.ts +21 -2
  29. package/dist/src/types.d.ts.map +1 -1
  30. package/dist/src/types.js.map +1 -1
  31. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  32. package/dist/src/workflow/steps/plan.js +26 -18
  33. package/dist/src/workflow/steps/plan.js.map +1 -1
  34. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  35. package/dist/src/workflow/steps/research.js +100 -66
  36. package/dist/src/workflow/steps/research.js.map +1 -1
  37. package/dist/src/workflow/types.d.ts +0 -2
  38. package/dist/src/workflow/types.d.ts.map +1 -1
  39. package/dist/templates/plan-template.md +1 -5
  40. package/package.json +2 -6
  41. package/src/agent.ts +7 -31
  42. package/src/agents/research.ts +84 -53
  43. package/src/file-manager.ts +18 -73
  44. package/src/git-manager.ts +7 -1
  45. package/src/posthog-api.ts +33 -1
  46. package/src/task-progress-reporter.ts +0 -1
  47. package/src/templates/plan-template.md +1 -5
  48. package/src/types.ts +25 -2
  49. package/src/workflow/steps/plan.ts +28 -21
  50. package/src/workflow/steps/research.ts +109 -74
  51. package/src/workflow/types.ts +0 -2
  52. package/dist/_virtual/_commonjsHelpers.js +0 -6
  53. package/dist/_virtual/_commonjsHelpers.js.map +0 -1
  54. package/dist/_virtual/index.js +0 -4
  55. package/dist/_virtual/index.js.map +0 -1
  56. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +0 -1154
  57. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +0 -1
  58. package/dist/node_modules/@ai-sdk/provider/dist/index.js +0 -296
  59. package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +0 -1
  60. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +0 -576
  61. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +0 -1
  62. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +0 -741
  63. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +0 -1
  64. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +0 -112
  65. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +0 -1
  66. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +0 -123
  67. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +0 -1
  68. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +0 -62
  69. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +0 -1
  70. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +0 -91
  71. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +0 -1
  72. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +0 -79
  73. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +0 -1
  74. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +0 -59
  75. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +0 -1
  76. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +0 -99
  77. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +0 -1
  78. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +0 -31
  79. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +0 -1
  80. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +0 -69
  81. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +0 -1
  82. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +0 -54
  83. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +0 -1
  84. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +0 -22
  85. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +0 -1
  86. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +0 -104
  87. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +0 -1
  88. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +0 -44
  89. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +0 -1
  90. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +0 -43
  91. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +0 -1
  92. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +0 -27
  93. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +0 -1
  94. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +0 -62
  95. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +0 -1
  96. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +0 -121
  97. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +0 -1
  98. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +0 -167
  99. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +0 -1
  100. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +0 -33
  101. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +0 -1
  102. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +0 -22
  103. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +0 -1
  104. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +0 -21
  105. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +0 -1
  106. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +0 -35
  107. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +0 -1
  108. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +0 -40
  109. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +0 -1
  110. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +0 -22
  111. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +0 -1
  112. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +0 -70
  113. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +0 -1
  114. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +0 -78
  115. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +0 -1
  116. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +0 -34
  117. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +0 -1
  118. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +0 -55
  119. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +0 -1
  120. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +0 -56
  121. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +0 -1
  122. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +0 -76
  123. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +0 -1
  124. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +0 -27
  125. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +0 -1
  126. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +0 -45
  127. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +0 -1
  128. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +0 -22
  129. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +0 -1
  130. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +0 -25
  131. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +0 -1
  132. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +0 -24
  133. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +0 -1
  134. package/dist/node_modules/@opentelemetry/api/build/esm/version.js +0 -20
  135. package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +0 -1
  136. package/dist/node_modules/ai/dist/index.js +0 -2870
  137. package/dist/node_modules/ai/dist/index.js.map +0 -1
  138. package/dist/node_modules/nanoid/non-secure/index.js +0 -13
  139. package/dist/node_modules/nanoid/non-secure/index.js.map +0 -1
  140. package/dist/node_modules/secure-json-parse/index.js +0 -133
  141. package/dist/node_modules/secure-json-parse/index.js.map +0 -1
  142. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +0 -37
  143. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +0 -1
  144. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +0 -26
  145. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +0 -1
  146. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +0 -17
  147. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +0 -1
  148. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +0 -11
  149. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +0 -1
  150. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +0 -8
  151. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +0 -1
  152. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +0 -66
  153. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +0 -1
  154. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +0 -21
  155. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +0 -1
  156. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +0 -30
  157. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +0 -1
  158. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +0 -53
  159. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +0 -1
  160. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +0 -8
  161. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +0 -1
  162. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +0 -8
  163. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +0 -1
  164. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +0 -8
  165. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +0 -1
  166. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +0 -50
  167. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +0 -1
  168. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +0 -11
  169. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +0 -1
  170. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +0 -11
  171. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +0 -1
  172. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +0 -9
  173. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +0 -1
  174. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +0 -56
  175. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +0 -1
  176. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +0 -24
  177. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +0 -1
  178. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +0 -30
  179. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +0 -1
  180. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +0 -19
  181. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +0 -1
  182. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +0 -15
  183. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +0 -1
  184. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +0 -13
  185. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +0 -1
  186. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +0 -37
  187. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +0 -1
  188. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +0 -56
  189. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +0 -1
  190. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +0 -76
  191. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +0 -1
  192. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +0 -25
  193. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +0 -1
  194. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +0 -24
  195. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +0 -1
  196. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +0 -8
  197. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +0 -1
  198. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +0 -8
  199. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +0 -1
  200. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +0 -65
  201. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +0 -1
  202. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +0 -24
  203. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +0 -1
  204. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +0 -350
  205. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +0 -1
  206. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +0 -36
  207. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +0 -1
  208. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +0 -10
  209. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +0 -1
  210. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +0 -84
  211. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +0 -1
  212. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +0 -8
  213. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +0 -1
  214. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +0 -110
  215. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +0 -1
  216. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +0 -90
  217. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +0 -1
  218. package/dist/src/structured-extraction.d.ts +0 -28
  219. package/dist/src/structured-extraction.d.ts.map +0 -1
  220. package/dist/src/structured-extraction.js +0 -77
  221. package/dist/src/structured-extraction.js.map +0 -1
  222. package/dist/src/utils/ai-sdk.d.ts +0 -14
  223. package/dist/src/utils/ai-sdk.d.ts.map +0 -1
  224. package/dist/src/utils/ai-sdk.js +0 -38
  225. package/dist/src/utils/ai-sdk.js.map +0 -1
  226. package/src/structured-extraction.ts +0 -117
  227. package/src/utils/ai-sdk.ts +0 -47
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
 
@@ -1,6 +1,6 @@
1
1
  import { promises as fs } from 'fs';
2
- import { join, dirname } from 'path';
3
- import type { SupportingFile } from './types.js';
2
+ import { join } from 'path';
3
+ import type { SupportingFile, ResearchEvaluation } from './types.js';
4
4
  import { Logger } from './utils/logger.js';
5
5
 
6
6
  export interface TaskFile {
@@ -9,24 +9,6 @@ export interface TaskFile {
9
9
  type: 'plan' | 'context' | 'reference' | 'output' | 'artifact';
10
10
  }
11
11
 
12
- export interface QuestionData {
13
- id: string;
14
- question: string;
15
- options: string[];
16
- }
17
-
18
- export interface AnswerData {
19
- questionId: string;
20
- selectedOption: string;
21
- customInput?: string;
22
- }
23
-
24
- export interface QuestionsFile {
25
- questions: QuestionData[];
26
- answered: boolean;
27
- answers: AnswerData[] | null;
28
- }
29
-
30
12
  export class PostHogFileManager {
31
13
  private repositoryPath: string;
32
14
  private logger: Logger;
@@ -170,48 +152,35 @@ export class PostHogFileManager {
170
152
  return await this.readTaskFile(taskId, 'requirements.md');
171
153
  }
172
154
 
173
- async writeResearch(taskId: string, content: string): Promise<void> {
155
+ async writeResearch(taskId: string, data: ResearchEvaluation): Promise<void> {
174
156
  this.logger.debug('Writing research', {
175
157
  taskId,
176
- contentLength: content.length,
177
- contentPreview: content.substring(0, 200)
158
+ score: data.actionabilityScore,
159
+ hasQuestions: !!data.questions,
160
+ questionCount: data.questions?.length ?? 0,
161
+ answered: data.answered ?? false,
178
162
  });
179
163
 
180
164
  await this.writeTaskFile(taskId, {
181
- name: 'research.md',
182
- content: content,
183
- type: 'artifact'
184
- });
185
-
186
- this.logger.info('Research file written', { taskId });
187
- }
188
-
189
- async readResearch(taskId: string): Promise<string | null> {
190
- return await this.readTaskFile(taskId, 'research.md');
191
- }
192
-
193
- async writeQuestions(taskId: string, data: QuestionsFile): Promise<void> {
194
- this.logger.debug('Writing questions', {
195
- taskId,
196
- questionCount: data.questions.length,
197
- answered: data.answered,
198
- });
199
-
200
- await this.writeTaskFile(taskId, {
201
- name: 'questions.json',
165
+ name: 'research.json',
202
166
  content: JSON.stringify(data, null, 2),
203
167
  type: 'artifact'
204
168
  });
205
169
 
206
- this.logger.info('Questions file written', { taskId });
170
+ this.logger.info('Research file written', {
171
+ taskId,
172
+ score: data.actionabilityScore,
173
+ hasQuestions: !!data.questions,
174
+ answered: data.answered ?? false,
175
+ });
207
176
  }
208
177
 
209
- async readQuestions(taskId: string): Promise<QuestionsFile | null> {
178
+ async readResearch(taskId: string): Promise<ResearchEvaluation | null> {
210
179
  try {
211
- const content = await this.readTaskFile(taskId, 'questions.json');
212
- return content ? JSON.parse(content) as QuestionsFile : null;
180
+ const content = await this.readTaskFile(taskId, 'research.json');
181
+ return content ? JSON.parse(content) as ResearchEvaluation : null;
213
182
  } catch (error) {
214
- this.logger.debug('Failed to parse questions.json', { error });
183
+ this.logger.debug('Failed to parse research.json', { error });
215
184
  return null;
216
185
  }
217
186
  }
@@ -241,28 +210,4 @@ export class PostHogFileManager {
241
210
 
242
211
  return files;
243
212
  }
244
-
245
- async ensureGitignore(): Promise<void> {
246
- const gitignorePath = join(this.repositoryPath, '.posthog', '.gitignore');
247
- const gitignoreContent = `# PostHog task artifacts - customize as needed
248
- # Exclude temporary files
249
- */temp/
250
- */cache/
251
- */.env
252
- */.secrets
253
-
254
- # Include plans and documentation by default
255
- !*/plan.md
256
- !*/context.md
257
- !*/requirements.md
258
- !*/README.md
259
- `;
260
-
261
- try {
262
- await fs.access(gitignorePath);
263
- } catch {
264
- await fs.mkdir(dirname(gitignorePath), { recursive: true });
265
- await fs.writeFile(gitignorePath, gitignoreContent, 'utf8');
266
- }
267
- }
268
213
  }
@@ -135,7 +135,13 @@ export class GitManager {
135
135
  }
136
136
 
137
137
  async addAllPostHogFiles(): Promise<void> {
138
- await this.runGitCommand('add .posthog/');
138
+ try {
139
+ // Use -A flag to add all changes (including new files) and ignore errors if directory is empty
140
+ await this.runGitCommand('add -A .posthog/');
141
+ } catch (error) {
142
+ // If the directory doesn't exist or has no files, that's fine - just log and continue
143
+ this.logger.debug('No PostHog files to add', { error });
144
+ }
139
145
  }
140
146
 
141
147
  async commitChanges(message: string, options?: {
@@ -11,7 +11,6 @@ export interface TaskRunUpdate {
11
11
  status?: TaskRun["status"];
12
12
  branch?: string | null;
13
13
  current_stage?: string | null;
14
- log?: LogEntry[];
15
14
  error_message?: string | null;
16
15
  output?: Record<string, unknown> | null;
17
16
  state?: Record<string, unknown>;
@@ -171,6 +170,39 @@ export class PostHogAPIClient {
171
170
  });
172
171
  }
173
172
 
173
+ /**
174
+ * Fetch logs from S3 using presigned URL from TaskRun
175
+ * @param taskRun - The task run containing the log_url
176
+ * @returns Array of log entries, or empty array if no logs available
177
+ */
178
+ async fetchTaskRunLogs(taskRun: TaskRun): Promise<LogEntry[]> {
179
+ if (!taskRun.log_url) {
180
+ return [];
181
+ }
182
+
183
+ try {
184
+ const response = await fetch(taskRun.log_url);
185
+
186
+ if (!response.ok) {
187
+ throw new Error(`Failed to fetch logs: ${response.status} ${response.statusText}`);
188
+ }
189
+
190
+ const content = await response.text();
191
+
192
+ if (!content.trim()) {
193
+ return [];
194
+ }
195
+
196
+ // Parse newline-delimited JSON
197
+ return content
198
+ .trim()
199
+ .split('\n')
200
+ .map(line => JSON.parse(line) as LogEntry);
201
+ } catch (error) {
202
+ throw new Error(`Failed to fetch task run logs: ${error instanceof Error ? error.message : String(error)}`);
203
+ }
204
+ }
205
+
174
206
  /**
175
207
  * Fetch error details from PostHog error tracking
176
208
  */
@@ -41,7 +41,6 @@ export class TaskProgressReporter {
41
41
  try {
42
42
  const run = await this.posthogAPI.createTaskRun(taskId, {
43
43
  status: 'started',
44
- log: [],
45
44
  });
46
45
  this.taskRun = run;
47
46
  this.outputLog = [];
@@ -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/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  // import and export to keep a single type file
3
- import type { CanUseTool, PermissionResult } from '@anthropic-ai/claude-agent-sdk/sdkTypes.js';
3
+ import type { CanUseTool, PermissionResult } from '@anthropic-ai/claude-agent-sdk';
4
4
  export type { CanUseTool, PermissionResult };
5
5
 
6
6
  // PostHog Task model (matches Array's OpenAPI schema)
@@ -39,7 +39,7 @@ export interface TaskRun {
39
39
  team: number;
40
40
  branch: string | null;
41
41
  status: 'started' | 'in_progress' | 'completed' | 'failed';
42
- log: LogEntry[]; // Array of log entry objects
42
+ log_url?: string; // Presigned S3 URL for log access (valid for 1 hour)
43
43
  error_message: string | null;
44
44
  output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)
45
45
  state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)
@@ -345,4 +345,27 @@ export interface UrlMention {
345
345
  type: ResourceType;
346
346
  id?: string;
347
347
  label?: string;
348
+ }
349
+
350
+ // Research evaluation types
351
+ export interface ResearchQuestion {
352
+ id: string;
353
+ question: string;
354
+ options: string[];
355
+ }
356
+
357
+ export interface ResearchAnswer {
358
+ questionId: string;
359
+ selectedOption: string;
360
+ customInput?: string;
361
+ }
362
+
363
+ export interface ResearchEvaluation {
364
+ actionabilityScore: number; // 0-1 confidence score
365
+ context: string; // brief summary for planning
366
+ keyFiles: string[]; // files needing modification
367
+ blockers?: string[]; // what's preventing full confidence
368
+ questions?: ResearchQuestion[]; // only if score < 0.7
369
+ answered?: boolean; // whether questions have been answered
370
+ answers?: ResearchAnswer[]; // user's answers to questions
348
371
  }
@@ -26,8 +26,8 @@ export const planStep: WorkflowStepRunner = async ({ step, context }) => {
26
26
  return { status: 'skipped' };
27
27
  }
28
28
 
29
- const questionsData = await fileManager.readQuestions(task.id);
30
- if (!questionsData || !questionsData.answered) {
29
+ const researchData = await fileManager.readResearch(task.id);
30
+ if (researchData?.questions && !researchData.answered) {
31
31
  stepLogger.info('Waiting for answered research questions', { taskId: task.id });
32
32
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
33
33
  return { status: 'skipped', halt: true };
@@ -35,29 +35,36 @@ export const planStep: WorkflowStepRunner = async ({ step, context }) => {
35
35
 
36
36
  stepLogger.info('Starting planning phase', { taskId: task.id });
37
37
  emitEvent(adapter.createStatusEvent('phase_start', { phase: 'planning' }));
38
-
39
- const researchContent = await fileManager.readResearch(task.id);
40
38
  let researchContext = '';
41
- if (researchContent) {
42
- researchContext += `## Research Analysis\n\n${researchContent}\n\n`;
43
- }
44
-
45
- researchContext += `## Implementation Decisions\n\n`;
46
- for (const question of questionsData.questions) {
47
- const answer = questionsData.answers?.find(
48
- (a: any) => a.questionId === question.id
49
- );
39
+ if (researchData) {
40
+ researchContext += `## Research Context\n\n${researchData.context}\n\n`;
41
+ if (researchData.keyFiles.length > 0) {
42
+ researchContext += `**Key Files:**\n${researchData.keyFiles.map(f => `- ${f}`).join('\n')}\n\n`;
43
+ }
44
+ if (researchData.blockers && researchData.blockers.length > 0) {
45
+ researchContext += `**Considerations:**\n${researchData.blockers.map(b => `- ${b}`).join('\n')}\n\n`;
46
+ }
50
47
 
51
- researchContext += `### ${question.question}\n\n`;
52
- if (answer) {
53
- researchContext += `**Selected:** ${answer.selectedOption}\n`;
54
- if (answer.customInput) {
55
- researchContext += `**Details:** ${answer.customInput}\n`;
48
+ // Add answered questions if they exist
49
+ if (researchData.questions && researchData.answers && researchData.answered) {
50
+ researchContext += `## Implementation Decisions\n\n`;
51
+ for (const question of researchData.questions) {
52
+ const answer = researchData.answers.find(
53
+ (a) => a.questionId === question.id
54
+ );
55
+
56
+ researchContext += `### ${question.question}\n\n`;
57
+ if (answer) {
58
+ researchContext += `**Selected:** ${answer.selectedOption}\n`;
59
+ if (answer.customInput) {
60
+ researchContext += `**Details:** ${answer.customInput}\n`;
61
+ }
62
+ } else {
63
+ researchContext += `**Selected:** Not answered\n`;
64
+ }
65
+ researchContext += `\n`;
56
66
  }
57
- } else {
58
- researchContext += `**Selected:** Not answered\n`;
59
67
  }
60
- researchContext += `\n`;
61
68
  }
62
69
 
63
70
  const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);