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