@posthog/agent 1.11.0 → 1.13.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 (268) hide show
  1. package/README.md +26 -65
  2. package/dist/_virtual/_commonjsHelpers.js +6 -0
  3. package/dist/_virtual/_commonjsHelpers.js.map +1 -0
  4. package/dist/_virtual/index.js +4 -0
  5. package/dist/_virtual/index.js.map +1 -0
  6. package/dist/index.d.ts +0 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +1154 -0
  9. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +1 -0
  10. package/dist/node_modules/@ai-sdk/provider/dist/index.js +296 -0
  11. package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +1 -0
  12. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +576 -0
  13. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +1 -0
  14. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +741 -0
  15. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +1 -0
  16. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +112 -0
  17. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +1 -0
  18. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +123 -0
  19. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +1 -0
  20. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +62 -0
  21. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +1 -0
  22. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +91 -0
  23. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +1 -0
  24. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +79 -0
  25. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +1 -0
  26. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +59 -0
  27. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +1 -0
  28. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +99 -0
  29. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +1 -0
  30. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +31 -0
  31. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +1 -0
  32. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +69 -0
  33. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +1 -0
  34. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +54 -0
  35. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +1 -0
  36. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +22 -0
  37. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +1 -0
  38. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +104 -0
  39. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +1 -0
  40. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +44 -0
  41. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +1 -0
  42. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +43 -0
  43. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +1 -0
  44. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +27 -0
  45. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +1 -0
  46. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +62 -0
  47. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +1 -0
  48. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +121 -0
  49. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +1 -0
  50. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +167 -0
  51. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +1 -0
  52. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +33 -0
  53. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +1 -0
  54. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +22 -0
  55. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +1 -0
  56. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +21 -0
  57. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +1 -0
  58. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +35 -0
  59. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +1 -0
  60. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +40 -0
  61. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +1 -0
  62. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +22 -0
  63. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +1 -0
  64. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +70 -0
  65. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +1 -0
  66. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +78 -0
  67. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +1 -0
  68. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +34 -0
  69. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +1 -0
  70. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +55 -0
  71. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +1 -0
  72. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +56 -0
  73. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +1 -0
  74. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +76 -0
  75. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +1 -0
  76. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +27 -0
  77. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +1 -0
  78. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +45 -0
  79. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +1 -0
  80. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +22 -0
  81. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +1 -0
  82. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +25 -0
  83. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +1 -0
  84. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +24 -0
  85. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +1 -0
  86. package/dist/node_modules/@opentelemetry/api/build/esm/version.js +20 -0
  87. package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +1 -0
  88. package/dist/node_modules/ai/dist/index.js +2870 -0
  89. package/dist/node_modules/ai/dist/index.js.map +1 -0
  90. package/dist/node_modules/nanoid/non-secure/index.js +13 -0
  91. package/dist/node_modules/nanoid/non-secure/index.js.map +1 -0
  92. package/dist/node_modules/secure-json-parse/index.js +133 -0
  93. package/dist/node_modules/secure-json-parse/index.js.map +1 -0
  94. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +37 -0
  95. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +1 -0
  96. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +26 -0
  97. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +1 -0
  98. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +17 -0
  99. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +1 -0
  100. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +11 -0
  101. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +1 -0
  102. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +8 -0
  103. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +1 -0
  104. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +66 -0
  105. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +1 -0
  106. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +21 -0
  107. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +1 -0
  108. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +30 -0
  109. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +1 -0
  110. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +53 -0
  111. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +1 -0
  112. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +8 -0
  113. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +1 -0
  114. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +8 -0
  115. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +1 -0
  116. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +8 -0
  117. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +1 -0
  118. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +50 -0
  119. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +1 -0
  120. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +11 -0
  121. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +1 -0
  122. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +11 -0
  123. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +1 -0
  124. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +9 -0
  125. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +1 -0
  126. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +56 -0
  127. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +1 -0
  128. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +24 -0
  129. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +1 -0
  130. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +30 -0
  131. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +1 -0
  132. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +19 -0
  133. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +1 -0
  134. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +15 -0
  135. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +1 -0
  136. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +13 -0
  137. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +1 -0
  138. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +37 -0
  139. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +1 -0
  140. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +56 -0
  141. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +1 -0
  142. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +76 -0
  143. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +1 -0
  144. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +25 -0
  145. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +1 -0
  146. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +24 -0
  147. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +1 -0
  148. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +8 -0
  149. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +1 -0
  150. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +8 -0
  151. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +1 -0
  152. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +65 -0
  153. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +1 -0
  154. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +24 -0
  155. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +1 -0
  156. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +350 -0
  157. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +1 -0
  158. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +36 -0
  159. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +1 -0
  160. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +10 -0
  161. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +1 -0
  162. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +84 -0
  163. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +1 -0
  164. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +8 -0
  165. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +1 -0
  166. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +110 -0
  167. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +1 -0
  168. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +90 -0
  169. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +1 -0
  170. package/dist/src/adapters/types.d.ts +1 -1
  171. package/dist/src/agent.d.ts +3 -13
  172. package/dist/src/agent.d.ts.map +1 -1
  173. package/dist/src/agent.js +94 -504
  174. package/dist/src/agent.js.map +1 -1
  175. package/dist/src/agents/execution.d.ts +1 -1
  176. package/dist/src/agents/execution.js +2 -2
  177. package/dist/src/agents/execution.js.map +1 -1
  178. package/dist/src/agents/planning.d.ts +1 -1
  179. package/dist/src/agents/planning.d.ts.map +1 -1
  180. package/dist/src/agents/planning.js +1 -2
  181. package/dist/src/agents/planning.js.map +1 -1
  182. package/dist/src/agents/research.d.ts +1 -1
  183. package/dist/src/agents/research.d.ts.map +1 -1
  184. package/dist/src/agents/research.js +3 -6
  185. package/dist/src/agents/research.js.map +1 -1
  186. package/dist/src/git-manager.js +1 -1
  187. package/dist/src/git-manager.js.map +1 -1
  188. package/dist/src/posthog-api.d.ts +0 -8
  189. package/dist/src/posthog-api.d.ts.map +1 -1
  190. package/dist/src/posthog-api.js +0 -32
  191. package/dist/src/posthog-api.js.map +1 -1
  192. package/dist/src/prompt-builder.d.ts.map +1 -1
  193. package/dist/src/prompt-builder.js +0 -1
  194. package/dist/src/prompt-builder.js.map +1 -1
  195. package/dist/src/structured-extraction.d.ts +2 -2
  196. package/dist/src/structured-extraction.d.ts.map +1 -1
  197. package/dist/src/structured-extraction.js +51 -110
  198. package/dist/src/structured-extraction.js.map +1 -1
  199. package/dist/src/task-progress-reporter.d.ts +0 -6
  200. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  201. package/dist/src/task-progress-reporter.js +2 -26
  202. package/dist/src/task-progress-reporter.js.map +1 -1
  203. package/dist/src/template-manager.d.ts.map +1 -1
  204. package/dist/src/template-manager.js +26 -4
  205. package/dist/src/template-manager.js.map +1 -1
  206. package/dist/src/types.d.ts +0 -4
  207. package/dist/src/types.d.ts.map +1 -1
  208. package/dist/src/types.js +0 -1
  209. package/dist/src/types.js.map +1 -1
  210. package/dist/src/workflow/config.d.ts +3 -0
  211. package/dist/src/workflow/config.d.ts.map +1 -0
  212. package/dist/src/workflow/config.js +43 -0
  213. package/dist/src/workflow/config.js.map +1 -0
  214. package/dist/src/workflow/steps/build.d.ts +3 -0
  215. package/dist/src/workflow/steps/build.d.ts.map +1 -0
  216. package/dist/src/workflow/steps/build.js +64 -0
  217. package/dist/src/workflow/steps/build.js.map +1 -0
  218. package/dist/src/workflow/steps/plan.d.ts +3 -0
  219. package/dist/src/workflow/steps/plan.d.ts.map +1 -0
  220. package/dist/src/workflow/steps/plan.js +86 -0
  221. package/dist/src/workflow/steps/plan.js.map +1 -0
  222. package/dist/src/workflow/steps/research.d.ts +3 -0
  223. package/dist/src/workflow/steps/research.d.ts.map +1 -0
  224. package/dist/src/workflow/steps/research.js +124 -0
  225. package/dist/src/workflow/steps/research.js.map +1 -0
  226. package/dist/src/workflow/types.d.ts +48 -0
  227. package/dist/src/workflow/types.d.ts.map +1 -0
  228. package/dist/src/workflow/utils.d.ts +12 -0
  229. package/dist/src/workflow/utils.d.ts.map +1 -0
  230. package/dist/src/workflow/utils.js +38 -0
  231. package/dist/src/workflow/utils.js.map +1 -0
  232. package/package.json +6 -4
  233. package/src/adapters/types.ts +1 -1
  234. package/src/agent.ts +114 -554
  235. package/src/agents/execution.ts +2 -2
  236. package/src/agents/planning.ts +1 -2
  237. package/src/agents/research.ts +3 -6
  238. package/src/git-manager.ts +1 -1
  239. package/src/posthog-api.ts +0 -40
  240. package/src/prompt-builder.ts +0 -2
  241. package/src/structured-extraction.ts +58 -115
  242. package/src/task-progress-reporter.ts +2 -34
  243. package/src/template-manager.ts +35 -5
  244. package/src/types.ts +0 -7
  245. package/src/workflow/config.ts +42 -0
  246. package/src/workflow/steps/build.ts +87 -0
  247. package/src/workflow/steps/plan.ts +112 -0
  248. package/src/workflow/steps/research.ts +156 -0
  249. package/src/workflow/types.ts +53 -0
  250. package/src/workflow/utils.ts +50 -0
  251. package/dist/src/agent-registry.d.ts +0 -16
  252. package/dist/src/agent-registry.d.ts.map +0 -1
  253. package/dist/src/agent-registry.js +0 -62
  254. package/dist/src/agent-registry.js.map +0 -1
  255. package/dist/src/stage-executor.d.ts +0 -20
  256. package/dist/src/stage-executor.d.ts.map +0 -1
  257. package/dist/src/stage-executor.js +0 -178
  258. package/dist/src/stage-executor.js.map +0 -1
  259. package/dist/src/workflow-registry.d.ts +0 -11
  260. package/dist/src/workflow-registry.d.ts.map +0 -1
  261. package/dist/src/workflow-registry.js +0 -27
  262. package/dist/src/workflow-registry.js.map +0 -1
  263. package/dist/src/workflow-types.d.ts +0 -45
  264. package/dist/src/workflow-types.d.ts.map +0 -1
  265. package/src/agent-registry.ts +0 -65
  266. package/src/stage-executor.ts +0 -210
  267. package/src/workflow-registry.ts +0 -30
  268. package/src/workflow-types.ts +0 -52
package/src/agent.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { query } from "@anthropic-ai/claude-agent-sdk";
2
- import type { Task, ExecutionResult, PlanResult, AgentConfig } from './types.js';
3
- import type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
2
+ import type { Task, ExecutionResult, AgentConfig } from './types.js';
4
3
  import { TaskManager } from './task-manager.js';
5
4
  import { PostHogAPIClient } from './posthog-api.js';
6
5
  import { PostHogFileManager } from './file-manager.js';
@@ -8,15 +7,12 @@ import { GitManager } from './git-manager.js';
8
7
  import { TemplateManager } from './template-manager.js';
9
8
  import { ClaudeAdapter } from './adapters/claude/claude-adapter.js';
10
9
  import type { ProviderAdapter } from './adapters/types.js';
11
- import { PLANNING_SYSTEM_PROMPT } from './agents/planning.js';
12
- import { EXECUTION_SYSTEM_PROMPT } from './agents/execution.js';
13
10
  import { Logger } from './utils/logger.js';
14
- import { AgentRegistry } from './agent-registry.js';
15
- import { WorkflowRegistry } from './workflow-registry.js';
16
- import { StageExecutor } from './stage-executor.js';
17
11
  import { PromptBuilder } from './prompt-builder.js';
18
12
  import { TaskProgressReporter } from './task-progress-reporter.js';
19
- import { OpenAIExtractor, type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
13
+ import { AISDKExtractor, type StructuredExtractor, type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
14
+ import { TASK_WORKFLOW } from './workflow/config.js';
15
+ import type { WorkflowRuntime } from './workflow/types.js';
20
16
 
21
17
  export class Agent {
22
18
  private workingDirectory: string;
@@ -28,12 +24,9 @@ export class Agent {
28
24
  private templateManager: TemplateManager;
29
25
  private adapter: ProviderAdapter;
30
26
  private logger: Logger;
31
- private agentRegistry: AgentRegistry;
32
- private workflowRegistry: WorkflowRegistry;
33
- private stageExecutor: StageExecutor;
34
27
  private progressReporter: TaskProgressReporter;
35
28
  private promptBuilder: PromptBuilder;
36
- private extractor?: OpenAIExtractor;
29
+ private extractor?: StructuredExtractor;
37
30
  private mcpServers?: Record<string, any>;
38
31
  public debug: boolean;
39
32
 
@@ -81,7 +74,6 @@ export class Agent {
81
74
  // TODO: Add author config from environment or config
82
75
  });
83
76
  this.templateManager = new TemplateManager();
84
- this.agentRegistry = new AgentRegistry();
85
77
 
86
78
  if (config.posthogApiUrl && config.posthogApiKey) {
87
79
  this.posthogAPI = new PostHogAPIClient({
@@ -90,27 +82,14 @@ export class Agent {
90
82
  });
91
83
  }
92
84
 
93
- this.workflowRegistry = new WorkflowRegistry(this.posthogAPI);
94
85
  this.promptBuilder = new PromptBuilder({
95
86
  getTaskFiles: (taskId: string) => this.getTaskFiles(taskId),
96
87
  generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
97
88
  posthogClient: this.posthogAPI,
98
89
  logger: this.logger.child('PromptBuilder')
99
90
  });
100
- this.stageExecutor = new StageExecutor(
101
- this.agentRegistry,
102
- this.logger,
103
- this.promptBuilder,
104
- undefined, // eventHandler set via setEventHandler below
105
- this.mcpServers
106
- );
107
- this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
108
91
  this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
109
-
110
- // Initialize OpenAI extractor if API key is available
111
- if (process.env.OPENAI_API_KEY) {
112
- this.extractor = new OpenAIExtractor(this.logger.child('OpenAIExtractor'));
113
- }
92
+ this.extractor = new AISDKExtractor(this.logger.child('AISDKExtractor'));
114
93
  }
115
94
 
116
95
  /**
@@ -130,6 +109,7 @@ export class Agent {
130
109
  }
131
110
 
132
111
  if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_AUTH_TOKEN) {
112
+ this.ensureOpenAIGatewayEnv();
133
113
  return;
134
114
  }
135
115
 
@@ -139,6 +119,7 @@ export class Agent {
139
119
 
140
120
  process.env.ANTHROPIC_BASE_URL = gatewayUrl;
141
121
  process.env.ANTHROPIC_AUTH_TOKEN = apiKey;
122
+ this.ensureOpenAIGatewayEnv(gatewayUrl, apiKey);
142
123
 
143
124
  this.logger.debug('Configured LLM gateway', { gatewayUrl });
144
125
  } catch (error) {
@@ -147,196 +128,7 @@ export class Agent {
147
128
  }
148
129
  }
149
130
 
150
- // Workflow-based execution
151
- async runWorkflow(taskOrId: Task | string, workflowId: string, options: WorkflowExecutionOptions = {}): Promise<{ task: Task; workflow: WorkflowDefinition }> {
152
- await this._configureLlmGateway();
153
-
154
- const task = typeof taskOrId === 'string' ? await this.fetchTask(taskOrId) : taskOrId;
155
- await this.workflowRegistry.loadWorkflows();
156
- const workflow = this.workflowRegistry.getWorkflow(workflowId);
157
- if (!workflow) {
158
- throw new Error(`Workflow ${workflowId} not found`);
159
- }
160
- const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
161
-
162
- // Ensure task is assigned to workflow and positioned at first stage
163
- if (this.posthogAPI) {
164
- try {
165
- if ((task.workflow as any) !== workflowId) {
166
- await this.posthogAPI.updateTask(task.id, { workflow: workflowId } as any);
167
- (task as any).workflow = workflowId;
168
- }
169
- } catch (e) {
170
- this.logger.warn('Failed to sync task workflow before execution', { error: (e as Error).message });
171
- }
172
- }
173
-
174
- const executionId = this.taskManager.generateExecutionId();
175
- this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
176
- this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
177
- await this.progressReporter.start(task.id, {
178
- totalSteps: orderedStages.length,
179
- });
180
-
181
- // Set initial stage on the newly created run
182
- const firstStage = orderedStages[0];
183
- if (this.posthogAPI && this.progressReporter.runId && firstStage) {
184
- try {
185
- await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
186
- current_stage: firstStage.id
187
- });
188
- } catch (e) {
189
- this.logger.warn('Failed to set initial stage on run', { error: (e as Error).message });
190
- }
191
- }
192
-
193
- try {
194
- let startIndex = 0;
195
- const currentStageId = (task as any).current_stage as string | undefined;
196
-
197
- // If task is already at the last stage, fail gracefully without progressing
198
- if (currentStageId) {
199
- const currIdx = orderedStages.findIndex(s => s.id === currentStageId);
200
- const atLastStage = currIdx >= 0 && currIdx === orderedStages.length - 1;
201
- if (atLastStage) {
202
- const finalStageKey = orderedStages[currIdx]?.key;
203
- this.emitEvent(this.adapter.createStatusEvent('no_next_stage', { stage: finalStageKey }));
204
- await this.progressReporter.noNextStage(finalStageKey);
205
- await this.progressReporter.complete();
206
- this.taskManager.completeExecution(executionId, { task, workflow });
207
- return { task, workflow };
208
- }
209
- }
210
-
211
- if (options.resumeFromCurrentStage && currentStageId) {
212
- const idx = orderedStages.findIndex(s => s.id === currentStageId);
213
- if (idx >= 0) startIndex = idx;
214
- }
215
-
216
- // Align server-side stage when restarting from a different stage
217
- if (this.posthogAPI && this.progressReporter.runId) {
218
- const targetStage = orderedStages[startIndex];
219
- if (targetStage && targetStage.id !== currentStageId) {
220
- try {
221
- await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
222
- current_stage: targetStage.id
223
- });
224
- } catch (e) {
225
- this.logger.warn('Failed to update run stage', { error: (e as Error).message });
226
- }
227
- }
228
- }
229
-
230
- for (let i = startIndex; i < orderedStages.length; i++) {
231
- const stage = orderedStages[i];
232
- await this.progressReporter.stageStarted(stage.key, i);
233
- await this.executeStage(task, stage, options);
234
- await this.progressReporter.stageCompleted(stage.key, i + 1);
235
- if (options.autoProgress) {
236
- const hasNext = i < orderedStages.length - 1;
237
- if (hasNext) {
238
- await this.progressToNextStage(task.id, stage.key);
239
- }
240
- }
241
- }
242
- await this.progressReporter.complete();
243
- this.taskManager.completeExecution(executionId, { task, workflow });
244
- return { task, workflow };
245
- } catch (error) {
246
- await this.progressReporter.fail(error as Error);
247
- this.taskManager.failExecution(executionId, error as Error);
248
- throw error;
249
- }
250
- }
251
-
252
- async executeStage(task: Task, stage: WorkflowStage, options: WorkflowExecutionOptions = {}): Promise<void> {
253
- this.emitEvent(this.adapter.createStatusEvent('stage_start', { stage: stage.key }));
254
- const overrides = options.stageOverrides?.[stage.key];
255
- const agentName = stage.agent_name || 'code_generation';
256
- const agentDef = this.agentRegistry.getAgent(agentName);
257
- const isManual = stage.is_manual_only === true;
258
- const stageKeyLower = (stage.key || '').toLowerCase().trim();
259
- const isPlanningByKey = stageKeyLower === 'plan' || stageKeyLower.includes('plan');
260
- const isPlanning = !isManual && ((agentDef?.agent_type === 'planning') || isPlanningByKey);
261
- const shouldCreatePlanningBranch = overrides?.createPlanningBranch !== false; // default true
262
- const shouldCreateImplBranch = overrides?.createImplementationBranch !== false; // default true
263
-
264
- if (isPlanning && shouldCreatePlanningBranch) {
265
- const planningBranch = await this.createPlanningBranch(task.id);
266
- await this.updateTaskBranch(task.id, planningBranch);
267
- this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: planningBranch }));
268
- await this.progressReporter.branchCreated(stage.key, planningBranch);
269
- } else if (!isPlanning && !isManual && shouldCreateImplBranch) {
270
- const implBranch = await this.createImplementationBranch(task.id);
271
- await this.updateTaskBranch(task.id, implBranch);
272
- this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
273
- await this.progressReporter.branchCreated(stage.key, implBranch);
274
- }
275
-
276
- const result = await this.stageExecutor.execute(task, stage, options);
277
-
278
- if (result.plan) {
279
- await this.writePlan(task.id, result.plan);
280
- await this.commitPlan(task.id, task.title);
281
- this.emitEvent(this.adapter.createStatusEvent('commit_made', { stage: stage.key, kind: 'plan' }));
282
- await this.progressReporter.commitMade(stage.key, 'plan');
283
- }
284
-
285
- if (isManual) {
286
- const defaultOpenPR = true; // manual stages default to PR for review
287
- const openPR = overrides?.openPullRequest ?? defaultOpenPR;
288
- if (openPR) {
289
- // Ensure we're on an implementation branch for PRs
290
- let branchName = await this.gitManager.getCurrentBranch();
291
- const onTaskBranch = branchName.includes(`posthog/task-${task.id}`);
292
- if (!onTaskBranch && (overrides?.createImplementationBranch !== false)) {
293
- const implBranch = await this.createImplementationBranch(task.id);
294
- await this.updateTaskBranch(task.id, implBranch);
295
- branchName = implBranch;
296
- this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
297
- await this.progressReporter.branchCreated(stage.key, implBranch);
298
- }
299
- try {
300
- const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
301
- await this.updateTaskBranch(task.id, branchName);
302
- await this.attachPullRequestToTask(task.id, prUrl, branchName);
303
- this.emitEvent(this.adapter.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
304
- await this.progressReporter.pullRequestCreated(stage.key, prUrl);
305
- } catch {}
306
- }
307
- // Do not auto-progress on manual stages
308
- this.emitEvent(this.adapter.createStatusEvent('stage_complete', { stage: stage.key }));
309
- return;
310
- }
311
-
312
- if (result.results) {
313
- const existingPlan = await this.readPlan(task.id);
314
- const planSummary = existingPlan ? existingPlan.split('\n')[0] : undefined;
315
- await this.commitImplementation(task.id, task.title, planSummary);
316
- this.emitEvent(this.adapter.createStatusEvent('commit_made', { stage: stage.key, kind: 'implementation' }));
317
- await this.progressReporter.commitMade(stage.key, 'implementation');
318
- }
319
-
320
- // PR creation on complete stage (or if explicitly requested), regardless of whether edits occurred
321
- {
322
- const defaultOpenPR = stage.key.toLowerCase().includes('complete');
323
- const openPR = overrides?.openPullRequest ?? defaultOpenPR;
324
- if (openPR) {
325
- const branchName = await this.gitManager.getCurrentBranch();
326
- try {
327
- const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
328
- await this.updateTaskBranch(task.id, branchName);
329
- await this.attachPullRequestToTask(task.id, prUrl, branchName);
330
- this.emitEvent(this.adapter.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
331
- await this.progressReporter.pullRequestCreated(stage.key, prUrl);
332
- } catch {}
333
- }
334
- }
335
-
336
- this.emitEvent(this.adapter.createStatusEvent('stage_complete', { stage: stage.key }));
337
- }
338
-
339
- // Adaptive task execution - 3-phase workflow (research → plan → build)
131
+ // Adaptive task execution orchestrated via workflow steps
340
132
  async runTask(taskOrId: Task | string, options: import('./types.js').TaskExecutionOptions = {}): Promise<void> {
341
133
  await this._configureLlmGateway();
342
134
 
@@ -348,351 +140,46 @@ export class Agent {
348
140
  this.logger.info('Starting adaptive task execution', { taskId: task.id, taskSlug, isCloudMode });
349
141
 
350
142
  // Initialize progress reporter for task run tracking (needed for PR attachment)
351
- await this.progressReporter.start(task.id, { totalSteps: 3 }); // 3 phases: research, plan, build
143
+ await this.progressReporter.start(task.id, { totalSteps: TASK_WORKFLOW.length });
352
144
  this.emitEvent(this.adapter.createStatusEvent('run_started', { runId: this.progressReporter.runId }));
353
145
 
354
- // Phase 1: Branch check
355
- const existingBranch = await this.gitManager.getTaskBranch(taskSlug);
356
- if (!existingBranch) {
357
- this.logger.info('Creating task branch', { taskSlug });
358
- const branchName = `posthog/task-${taskSlug}`;
359
- await this.gitManager.createOrSwitchToBranch(branchName);
360
- this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
361
-
362
- // Initial commit
363
- await this.fileManager.ensureGitignore();
364
- await this.gitManager.addAllPostHogFiles();
365
- if (isCloudMode) {
366
- await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
367
- } else {
368
- await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
369
- }
370
- } else {
371
- this.logger.info('Switching to existing task branch', { branch: existingBranch });
372
- await this.gitManager.switchToBranch(existingBranch);
373
- }
374
-
375
- // Phase 2: Research
376
- const researchExists = await this.fileManager.readResearch(task.id);
377
- if (!researchExists) {
378
- this.logger.info('Starting research phase', { taskId: task.id });
379
- this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'research' }));
380
-
381
- // Run research agent
382
- const researchPrompt = await this.promptBuilder.buildResearchPrompt(task, cwd);
383
- const { RESEARCH_SYSTEM_PROMPT } = await import('./agents/research.js');
384
- const fullPrompt = RESEARCH_SYSTEM_PROMPT + '\n\n' + researchPrompt;
385
-
386
- const baseOptions: Record<string, any> = {
387
- model: 'claude-sonnet-4-5-20250929',
388
- cwd,
389
- permissionMode: 'plan',
390
- settingSources: ['local'],
391
- mcpServers: this.mcpServers,
392
- };
393
-
394
- const response = query({
395
- prompt: fullPrompt,
396
- options: { ...baseOptions, ...(options.queryOverrides || {}) },
397
- });
398
-
399
- let researchContent = '';
400
- for await (const message of response) {
401
- this.emitEvent(this.adapter.createRawSDKEvent(message));
402
- const transformed = this.adapter.transform(message);
403
- if (transformed) {
404
- this.emitEvent(transformed);
405
- }
406
- if (message.type === 'assistant' && message.message?.content) {
407
- for (const c of message.message.content) {
408
- if (c.type === 'text' && c.text) researchContent += c.text + '\n';
409
- }
410
- }
411
- }
412
-
413
- // Write research.md
414
- if (researchContent.trim()) {
415
- await this.fileManager.writeResearch(task.id, researchContent.trim());
416
- this.logger.info('Research completed', { taskId: task.id });
417
- }
146
+ await this.prepareTaskBranch(taskSlug, isCloudMode);
147
+
148
+ const workflowContext: WorkflowRuntime = {
149
+ task,
150
+ taskSlug,
151
+ cwd,
152
+ isCloudMode,
153
+ options,
154
+ logger: this.logger,
155
+ fileManager: this.fileManager,
156
+ gitManager: this.gitManager,
157
+ promptBuilder: this.promptBuilder,
158
+ progressReporter: this.progressReporter,
159
+ adapter: this.adapter,
160
+ mcpServers: this.mcpServers,
161
+ posthogAPI: this.posthogAPI,
162
+ extractor: this.extractor,
163
+ emitEvent: (event: any) => this.emitEvent(event),
164
+ stepResults: {},
165
+ };
418
166
 
419
- // Commit research
420
- await this.gitManager.addAllPostHogFiles();
421
-
422
- // Extract questions using structured output and save to questions.json
423
- if (this.extractor) {
424
- try {
425
- this.logger.info('Extracting questions from research.md', { taskId: task.id });
426
- const questions = await this.extractQuestionsFromResearch(task.id, false);
427
-
428
- this.logger.info('Questions extracted successfully', { taskId: task.id, count: questions.length });
429
-
430
- // Save questions.json
431
- await this.fileManager.writeQuestions(task.id, {
432
- questions,
433
- answered: false,
434
- answers: null,
435
- });
436
-
437
- this.logger.info('Questions saved to questions.json', { taskId: task.id });
438
-
439
- // Emit event for Array to pick up (local mode)
440
- if (!isCloudMode) {
441
- this.emitEvent({
442
- type: 'artifact',
443
- ts: Date.now(),
444
- kind: 'research_questions',
445
- content: questions,
446
- });
447
- this.logger.info('Emitted research_questions artifact event', { taskId: task.id });
448
- }
449
- } catch (error) {
450
- this.logger.error('Failed to extract questions', { error: error instanceof Error ? error.message : String(error) });
451
- this.emitEvent({
452
- type: 'error',
453
- ts: Date.now(),
454
- message: `Failed to extract questions: ${error instanceof Error ? error.message : String(error)}`,
455
- });
456
- }
457
- } else {
458
- this.logger.warn('OpenAI extractor not available (OPENAI_API_KEY not set), skipping question extraction');
459
- this.emitEvent({
460
- type: 'status',
461
- ts: Date.now(),
462
- phase: 'extraction_skipped',
463
- message: 'Question extraction skipped - OPENAI_API_KEY not configured',
464
- });
465
- }
466
-
467
- if (isCloudMode) {
468
- await this.gitManager.commitAndPush(`Research phase for ${task.title}`);
469
- } else {
470
- await this.gitManager.commitChanges(`Research phase for ${task.title}`);
471
- this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research' }));
472
- return; // Local mode: return to user
167
+ for (const step of TASK_WORKFLOW) {
168
+ const result = await step.run({ step, context: workflowContext });
169
+ if (result.halt) {
170
+ return;
473
171
  }
474
172
  }
475
173
 
476
- // Phase 3: Auto-answer questions (cloud mode only)
477
174
  if (isCloudMode) {
478
- const questionsData = await this.fileManager.readQuestions(task.id);
479
- if (questionsData && !questionsData.answered) {
480
- this.logger.info('Auto-answering research questions', { taskId: task.id });
481
-
482
- // Extract questions with recommended answers using structured output
483
- if (this.extractor) {
484
- const questionsWithAnswers = await this.extractQuestionsFromResearch(task.id, true) as ExtractedQuestionWithAnswer[];
485
-
486
- // Save answers to questions.json
487
- await this.fileManager.writeQuestions(task.id, {
488
- questions: questionsWithAnswers.map(qa => ({
489
- id: qa.id,
490
- question: qa.question,
491
- options: qa.options,
492
- })),
493
- answered: true,
494
- answers: questionsWithAnswers.map(qa => ({
495
- questionId: qa.id,
496
- selectedOption: qa.recommendedAnswer,
497
- customInput: qa.justification,
498
- })),
499
- });
500
-
501
- this.logger.info('Auto-answers saved to questions.json', { taskId: task.id });
502
- await this.gitManager.addAllPostHogFiles();
503
- await this.gitManager.commitAndPush(`Answer research questions for ${task.title}`);
504
- } else {
505
- this.logger.warn('OpenAI extractor not available, skipping auto-answer');
506
- }
507
- }
508
- }
509
-
510
- // Phase 4: Plan
511
- const planExists = await this.readPlan(task.id);
512
- if (!planExists) {
513
- // Check if questions have been answered
514
- const questionsData = await this.fileManager.readQuestions(task.id);
515
- if (!questionsData || !questionsData.answered) {
516
- this.logger.info('Waiting for user answers to research questions');
517
- this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
518
- return; // Wait for user to answer questions
519
- }
520
-
521
- this.logger.info('Starting planning phase', { taskId: task.id });
522
- this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'planning' }));
523
-
524
- // Build context with research + questions + answers
525
- const research = await this.fileManager.readResearch(task.id);
526
- let researchContext = '';
527
- if (research) {
528
- researchContext += `## Research Analysis\n\n${research}\n\n`;
529
- }
530
-
531
- // Add questions and answers
532
- researchContext += `## Implementation Decisions\n\n`;
533
- const answers = questionsData.answers || [];
534
- for (const question of questionsData.questions) {
535
- const answer = answers.find((a: any) => a.questionId === question.id);
536
-
537
- researchContext += `### ${question.question}\n\n`;
538
- if (answer) {
539
- researchContext += `**Selected:** ${answer.selectedOption}\n`;
540
- if (answer.customInput) {
541
- researchContext += `**Details:** ${answer.customInput}\n`;
542
- }
543
- } else {
544
- this.logger.warn('No answer found for question', { questionId: question.id });
545
- researchContext += `**Selected:** Not answered\n`;
546
- }
547
- researchContext += '\n';
548
- }
549
-
550
- // Run planning agent with full context
551
- const planningPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);
552
- const { PLANNING_SYSTEM_PROMPT } = await import('./agents/planning.js');
553
- const fullPrompt = PLANNING_SYSTEM_PROMPT + '\n\n' + planningPrompt + '\n\n' + researchContext;
554
-
555
- const baseOptions: Record<string, any> = {
556
- model: 'claude-sonnet-4-5-20250929',
557
- cwd,
558
- permissionMode: 'plan',
559
- settingSources: ['local'],
560
- mcpServers: this.mcpServers,
561
- };
562
-
563
- const response = query({
564
- prompt: fullPrompt,
565
- options: { ...baseOptions, ...(options.queryOverrides || {}) },
566
- });
567
-
568
- let planContent = '';
569
- for await (const message of response) {
570
- this.emitEvent(this.adapter.createRawSDKEvent(message));
571
- const transformed = this.adapter.transform(message);
572
- if (transformed) {
573
- this.emitEvent(transformed);
574
- }
575
- if (message.type === 'assistant' && message.message?.content) {
576
- for (const c of message.message.content) {
577
- if (c.type === 'text' && c.text) planContent += c.text + '\n';
578
- }
579
- }
580
- }
581
-
582
- // Write plan.md
583
- if (planContent.trim()) {
584
- await this.writePlan(task.id, planContent.trim());
585
- this.logger.info('Plan completed', { taskId: task.id });
586
- }
587
-
588
- // Commit plan
589
- await this.gitManager.addAllPostHogFiles();
590
- if (isCloudMode) {
591
- await this.gitManager.commitAndPush(`Planning phase for ${task.title}`);
592
- } else {
593
- await this.gitManager.commitChanges(`Planning phase for ${task.title}`);
594
- this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'planning' }));
595
- return; // Local mode: return to user
596
- }
175
+ await this.ensurePullRequest(task, workflowContext.stepResults);
597
176
  }
598
177
 
599
- // Phase 5: Build
600
- const latestRun = task.latest_run;
601
- const prExists = latestRun?.output && (latestRun.output as any).pr_url;
602
-
603
- if (!prExists) {
604
- this.logger.info('Starting build phase', { taskId: task.id });
605
- this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'build' }));
606
-
607
- // Run execution agent
608
- const executionPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);
609
- const { EXECUTION_SYSTEM_PROMPT } = await import('./agents/execution.js');
610
- const fullPrompt = EXECUTION_SYSTEM_PROMPT + '\n\n' + executionPrompt;
611
-
612
- const { PermissionMode } = await import('./types.js');
613
- const permissionMode = options.permissionMode || PermissionMode.ACCEPT_EDITS;
614
- const baseOptions: Record<string, any> = {
615
- model: 'claude-sonnet-4-5-20250929',
616
- cwd,
617
- permissionMode,
618
- settingSources: ['local'],
619
- mcpServers: this.mcpServers,
620
- };
621
-
622
- const response = query({
623
- prompt: fullPrompt,
624
- options: { ...baseOptions, ...(options.queryOverrides || {}) },
625
- });
626
-
627
- for await (const message of response) {
628
- this.emitEvent(this.adapter.createRawSDKEvent(message));
629
- const transformed = this.adapter.transform(message);
630
- if (transformed) {
631
- this.emitEvent(transformed);
632
- }
633
- }
634
-
635
- // Commit and push implementation
636
- // Stage ALL changes (not just .posthog/)
637
- const hasChanges = await this.gitManager.hasChanges();
638
- if (hasChanges) {
639
- await this.gitManager.addFiles(['.']); // Stage all changes
640
- await this.gitManager.commitChanges(`Implementation for ${task.title}`);
641
-
642
- // Push to origin
643
- const branchName = await this.gitManager.getCurrentBranch();
644
- await this.gitManager.pushBranch(branchName);
645
-
646
- this.logger.info('Implementation committed and pushed', { taskId: task.id });
647
- } else {
648
- this.logger.warn('No changes to commit in build phase', { taskId: task.id });
649
- }
650
-
651
- // Create PR
652
- const branchName = await this.gitManager.getCurrentBranch();
653
- const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
654
- this.logger.info('Pull request created', { taskId: task.id, prUrl });
655
- this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
656
-
657
- // Attach PR to task run
658
- try {
659
- await this.attachPullRequestToTask(task.id, prUrl, branchName);
660
- this.logger.info('PR attached to task successfully', { taskId: task.id, prUrl });
661
- } catch (error) {
662
- this.logger.warn('Could not attach PR to task', { error: error instanceof Error ? error.message : String(error) });
663
- }
664
- } else {
665
- this.logger.info('PR already exists, skipping build phase', { taskId: task.id });
666
- }
667
-
668
- // Phase 6: Complete
669
178
  await this.progressReporter.complete();
670
179
  this.logger.info('Task execution complete', { taskId: task.id });
671
180
  this.emitEvent(this.adapter.createStatusEvent('task_complete', { taskId: task.id }));
672
181
  }
673
182
 
674
- async progressToNextStage(taskId: string, currentStageKey?: string): Promise<void> {
675
- if (!this.posthogAPI || !this.progressReporter.runId) {
676
- throw new Error('PostHog API not configured or no active run. Cannot progress stage.');
677
- }
678
- try {
679
- await this.posthogAPI.progressTaskRun(taskId, this.progressReporter.runId);
680
- } catch (error) {
681
- if (error instanceof Error && error.message.includes('No next stage available')) {
682
- this.logger.warn('No next stage available when attempting to progress run', {
683
- taskId,
684
- runId: this.progressReporter.runId,
685
- stage: currentStageKey,
686
- error: error.message,
687
- });
688
- this.emitEvent(this.adapter.createStatusEvent('no_next_stage', { stage: currentStageKey }));
689
- await this.progressReporter.noNextStage(currentStageKey);
690
- return;
691
- }
692
- throw error;
693
- }
694
- }
695
-
696
183
  // Direct prompt execution - still supported for low-level usage
697
184
  async run(prompt: string, options: { repositoryPath?: string; permissionMode?: import('./types.js').PermissionMode; queryOverrides?: Record<string, any> } = {}): Promise<ExecutionResult> {
698
185
  await this._configureLlmGateway();
@@ -744,8 +231,6 @@ export class Agent {
744
231
  repository?: string;
745
232
  organization?: string;
746
233
  origin_product?: string;
747
- workflow?: string;
748
- current_stage?: string;
749
234
  }): Promise<Task[]> {
750
235
  if (!this.posthogAPI) {
751
236
  throw new Error('PostHog API not configured. Provide posthogApiUrl and posthogApiKey in constructor.');
@@ -785,7 +270,7 @@ export class Agent {
785
270
  this.logger.info('Extracting questions from research.md', { taskId, includeAnswers });
786
271
 
787
272
  if (!this.extractor) {
788
- throw new Error('OpenAI extractor not initialized. Set OPENAI_API_KEY environment variable.');
273
+ throw new Error('OpenAI extractor not initialized. Ensure the LLM gateway is configured.');
789
274
  }
790
275
 
791
276
  const researchContent = await this.fileManager.readResearch(taskId);
@@ -799,8 +284,8 @@ export class Agent {
799
284
  return await this.extractor.extractQuestions(researchContent);
800
285
  }
801
286
  }
802
-
803
- // Git operations for task workflow
287
+
288
+ // Git operations for task execution
804
289
  async createPlanningBranch(taskId: string): Promise<string> {
805
290
  this.logger.info('Creating planning branch', { taskId });
806
291
  const branchName = await this.gitManager.createTaskPlanningBranch(taskId);
@@ -908,6 +393,82 @@ Generated by PostHog Agent`;
908
393
  return null;
909
394
  }
910
395
 
396
+ private async prepareTaskBranch(taskSlug: string, isCloudMode: boolean): Promise<void> {
397
+ const existingBranch = await this.gitManager.getTaskBranch(taskSlug);
398
+ if (!existingBranch) {
399
+ this.logger.info('Creating task branch', { taskSlug });
400
+ const branchName = `posthog/task-${taskSlug}`;
401
+ await this.gitManager.createOrSwitchToBranch(branchName);
402
+ this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
403
+
404
+ await this.fileManager.ensureGitignore();
405
+ await this.gitManager.addAllPostHogFiles();
406
+ if (isCloudMode) {
407
+ await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
408
+ } else {
409
+ await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
410
+ }
411
+ } else {
412
+ this.logger.info('Switching to existing task branch', { branch: existingBranch });
413
+ await this.gitManager.switchToBranch(existingBranch);
414
+ }
415
+ }
416
+
417
+ private ensureOpenAIGatewayEnv(baseUrl?: string, token?: string): void {
418
+ const resolvedBaseUrl = baseUrl || process.env.ANTHROPIC_BASE_URL;
419
+ const resolvedToken = token || process.env.ANTHROPIC_AUTH_TOKEN;
420
+
421
+ if (resolvedBaseUrl) {
422
+ process.env.OPENAI_BASE_URL = resolvedBaseUrl;
423
+ }
424
+
425
+ if (resolvedToken) {
426
+ process.env.OPENAI_API_KEY = resolvedToken;
427
+ }
428
+
429
+ if (!this.extractor) {
430
+ this.extractor = new AISDKExtractor(this.logger.child('AISDKExtractor'));
431
+ }
432
+ }
433
+
434
+ private async ensurePullRequest(task: Task, stepResults: Record<string, any>): Promise<void> {
435
+ const latestRun = task.latest_run;
436
+ const existingPr =
437
+ latestRun?.output && typeof latestRun.output === 'object'
438
+ ? (latestRun.output as any).pr_url
439
+ : null;
440
+
441
+ if (existingPr) {
442
+ this.logger.info('PR already exists, skipping creation', { taskId: task.id, prUrl: existingPr });
443
+ return;
444
+ }
445
+
446
+ const buildResult = stepResults['build'];
447
+ if (!buildResult?.commitCreated) {
448
+ this.logger.warn('Build step did not produce a commit; skipping PR creation', { taskId: task.id });
449
+ return;
450
+ }
451
+
452
+ const branchName = await this.gitManager.getCurrentBranch();
453
+ const prUrl = await this.createPullRequest(
454
+ task.id,
455
+ branchName,
456
+ task.title,
457
+ task.description ?? ''
458
+ );
459
+
460
+ this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
461
+
462
+ try {
463
+ await this.attachPullRequestToTask(task.id, prUrl, branchName);
464
+ this.logger.info('PR attached to task successfully', { taskId: task.id, prUrl });
465
+ } catch (error) {
466
+ this.logger.warn('Could not attach PR to task', {
467
+ error: error instanceof Error ? error.message : String(error),
468
+ });
469
+ }
470
+ }
471
+
911
472
  private emitEvent(event: any): void {
912
473
  if (this.debug && event.type !== 'token') {
913
474
  // Log all events except tokens (too verbose)
@@ -925,4 +486,3 @@ Generated by PostHog Agent`;
925
486
 
926
487
  export { PermissionMode } from './types.js';
927
488
  export type { Task, SupportingFile, ExecutionResult, AgentConfig } from './types.js';
928
- export type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';