@posthog/agent 1.12.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 (219) hide show
  1. package/dist/_virtual/_commonjsHelpers.js +6 -0
  2. package/dist/_virtual/_commonjsHelpers.js.map +1 -0
  3. package/dist/_virtual/index.js +4 -0
  4. package/dist/_virtual/index.js.map +1 -0
  5. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +1154 -0
  6. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +1 -0
  7. package/dist/node_modules/@ai-sdk/provider/dist/index.js +296 -0
  8. package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +1 -0
  9. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +576 -0
  10. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +1 -0
  11. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +741 -0
  12. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +1 -0
  13. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +112 -0
  14. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +1 -0
  15. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +123 -0
  16. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +1 -0
  17. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +62 -0
  18. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +1 -0
  19. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +91 -0
  20. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +1 -0
  21. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +79 -0
  22. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +1 -0
  23. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +59 -0
  24. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +1 -0
  25. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +99 -0
  26. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +1 -0
  27. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +31 -0
  28. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +1 -0
  29. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +69 -0
  30. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +1 -0
  31. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +54 -0
  32. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +1 -0
  33. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +22 -0
  34. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +1 -0
  35. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +104 -0
  36. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +1 -0
  37. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +44 -0
  38. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +1 -0
  39. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +43 -0
  40. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +1 -0
  41. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +27 -0
  42. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +1 -0
  43. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +62 -0
  44. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +1 -0
  45. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +121 -0
  46. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +1 -0
  47. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +167 -0
  48. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +1 -0
  49. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +33 -0
  50. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +1 -0
  51. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +22 -0
  52. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +1 -0
  53. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +21 -0
  54. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +1 -0
  55. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +35 -0
  56. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +1 -0
  57. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +40 -0
  58. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +1 -0
  59. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +22 -0
  60. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +1 -0
  61. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +70 -0
  62. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +1 -0
  63. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +78 -0
  64. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +1 -0
  65. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +34 -0
  66. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +1 -0
  67. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +55 -0
  68. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +1 -0
  69. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +56 -0
  70. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +1 -0
  71. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +76 -0
  72. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +1 -0
  73. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +27 -0
  74. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +1 -0
  75. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +45 -0
  76. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +1 -0
  77. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +22 -0
  78. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +1 -0
  79. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +25 -0
  80. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +1 -0
  81. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +24 -0
  82. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +1 -0
  83. package/dist/node_modules/@opentelemetry/api/build/esm/version.js +20 -0
  84. package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +1 -0
  85. package/dist/node_modules/ai/dist/index.js +2870 -0
  86. package/dist/node_modules/ai/dist/index.js.map +1 -0
  87. package/dist/node_modules/nanoid/non-secure/index.js +13 -0
  88. package/dist/node_modules/nanoid/non-secure/index.js.map +1 -0
  89. package/dist/node_modules/secure-json-parse/index.js +133 -0
  90. package/dist/node_modules/secure-json-parse/index.js.map +1 -0
  91. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +37 -0
  92. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +1 -0
  93. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +26 -0
  94. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +1 -0
  95. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +17 -0
  96. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +1 -0
  97. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +11 -0
  98. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +1 -0
  99. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +8 -0
  100. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +1 -0
  101. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +66 -0
  102. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +1 -0
  103. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +21 -0
  104. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +1 -0
  105. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +30 -0
  106. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +1 -0
  107. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +53 -0
  108. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +1 -0
  109. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +8 -0
  110. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +1 -0
  111. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +8 -0
  112. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +1 -0
  113. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +8 -0
  114. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +1 -0
  115. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +50 -0
  116. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +1 -0
  117. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +11 -0
  118. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +1 -0
  119. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +11 -0
  120. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +1 -0
  121. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +9 -0
  122. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +1 -0
  123. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +56 -0
  124. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +1 -0
  125. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +24 -0
  126. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +1 -0
  127. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +30 -0
  128. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +1 -0
  129. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +19 -0
  130. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +1 -0
  131. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +15 -0
  132. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +1 -0
  133. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +13 -0
  134. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +1 -0
  135. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +37 -0
  136. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +1 -0
  137. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +56 -0
  138. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +1 -0
  139. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +76 -0
  140. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +1 -0
  141. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +25 -0
  142. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +1 -0
  143. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +24 -0
  144. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +1 -0
  145. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +8 -0
  146. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +1 -0
  147. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +8 -0
  148. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +1 -0
  149. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +65 -0
  150. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +1 -0
  151. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +24 -0
  152. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +1 -0
  153. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +350 -0
  154. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +1 -0
  155. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +36 -0
  156. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +1 -0
  157. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +10 -0
  158. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +1 -0
  159. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +84 -0
  160. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +1 -0
  161. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +8 -0
  162. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +1 -0
  163. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +110 -0
  164. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +1 -0
  165. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +90 -0
  166. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +1 -0
  167. package/dist/src/agent.d.ts +3 -0
  168. package/dist/src/agent.d.ts.map +1 -1
  169. package/dist/src/agent.js +93 -291
  170. package/dist/src/agent.js.map +1 -1
  171. package/dist/src/agents/planning.d.ts +1 -1
  172. package/dist/src/agents/planning.d.ts.map +1 -1
  173. package/dist/src/agents/planning.js +1 -2
  174. package/dist/src/agents/planning.js.map +1 -1
  175. package/dist/src/agents/research.d.ts +1 -1
  176. package/dist/src/agents/research.d.ts.map +1 -1
  177. package/dist/src/agents/research.js +3 -6
  178. package/dist/src/agents/research.js.map +1 -1
  179. package/dist/src/prompt-builder.d.ts.map +1 -1
  180. package/dist/src/prompt-builder.js +0 -1
  181. package/dist/src/prompt-builder.js.map +1 -1
  182. package/dist/src/structured-extraction.d.ts +2 -2
  183. package/dist/src/structured-extraction.d.ts.map +1 -1
  184. package/dist/src/structured-extraction.js +51 -110
  185. package/dist/src/structured-extraction.js.map +1 -1
  186. package/dist/src/workflow/config.d.ts +3 -0
  187. package/dist/src/workflow/config.d.ts.map +1 -0
  188. package/dist/src/workflow/config.js +43 -0
  189. package/dist/src/workflow/config.js.map +1 -0
  190. package/dist/src/workflow/steps/build.d.ts +3 -0
  191. package/dist/src/workflow/steps/build.d.ts.map +1 -0
  192. package/dist/src/workflow/steps/build.js +64 -0
  193. package/dist/src/workflow/steps/build.js.map +1 -0
  194. package/dist/src/workflow/steps/plan.d.ts +3 -0
  195. package/dist/src/workflow/steps/plan.d.ts.map +1 -0
  196. package/dist/src/workflow/steps/plan.js +86 -0
  197. package/dist/src/workflow/steps/plan.js.map +1 -0
  198. package/dist/src/workflow/steps/research.d.ts +3 -0
  199. package/dist/src/workflow/steps/research.d.ts.map +1 -0
  200. package/dist/src/workflow/steps/research.js +124 -0
  201. package/dist/src/workflow/steps/research.js.map +1 -0
  202. package/dist/src/workflow/types.d.ts +48 -0
  203. package/dist/src/workflow/types.d.ts.map +1 -0
  204. package/dist/src/workflow/utils.d.ts +12 -0
  205. package/dist/src/workflow/utils.d.ts.map +1 -0
  206. package/dist/src/workflow/utils.js +38 -0
  207. package/dist/src/workflow/utils.js.map +1 -0
  208. package/package.json +5 -2
  209. package/src/agent.ts +112 -321
  210. package/src/agents/planning.ts +1 -2
  211. package/src/agents/research.ts +3 -6
  212. package/src/prompt-builder.ts +0 -2
  213. package/src/structured-extraction.ts +58 -115
  214. package/src/workflow/config.ts +42 -0
  215. package/src/workflow/steps/build.ts +87 -0
  216. package/src/workflow/steps/plan.ts +112 -0
  217. package/src/workflow/steps/research.ts +156 -0
  218. package/src/workflow/types.ts +53 -0
  219. package/src/workflow/utils.ts +50 -0
@@ -1,4 +1,6 @@
1
- import OpenAI from 'openai';
1
+ import { generateObject } from 'ai';
2
+ import { anthropic } from '@ai-sdk/anthropic';
3
+ import { z } from 'zod';
2
4
  import { Logger } from './utils/logger.js';
3
5
 
4
6
  export interface ExtractedQuestion {
@@ -12,73 +14,54 @@ export interface ExtractedQuestionWithAnswer extends ExtractedQuestion {
12
14
  justification: string;
13
15
  }
14
16
 
15
- const questionsOnlySchema = {
16
- type: 'object',
17
- properties: {
18
- questions: {
19
- type: 'array',
20
- items: {
21
- type: 'object',
22
- properties: {
23
- id: { type: 'string' },
24
- question: { type: 'string' },
25
- options: {
26
- type: 'array',
27
- items: { type: 'string' }
28
- }
29
- },
30
- required: ['id', 'question', 'options'],
31
- additionalProperties: false
32
- }
33
- }
34
- },
35
- required: ['questions'],
36
- additionalProperties: false
37
- };
38
-
39
- const questionsWithAnswersSchema = {
40
- type: 'object',
41
- properties: {
42
- questions: {
43
- type: 'array',
44
- items: {
45
- type: 'object',
46
- properties: {
47
- id: { type: 'string' },
48
- question: { type: 'string' },
49
- options: {
50
- type: 'array',
51
- items: { type: 'string' }
52
- },
53
- recommendedAnswer: { type: 'string' },
54
- justification: { type: 'string' }
55
- },
56
- required: ['id', 'question', 'options', 'recommendedAnswer', 'justification'],
57
- additionalProperties: false
58
- }
59
- }
60
- },
61
- required: ['questions'],
62
- additionalProperties: false
63
- };
17
+ const questionsOnlySchema = z.object({
18
+ questions: z.array(
19
+ z.object({
20
+ id: z.string(),
21
+ question: z.string(),
22
+ options: z.array(z.string()),
23
+ })
24
+ ),
25
+ });
26
+
27
+ const questionsWithAnswersSchema = z.object({
28
+ questions: z.array(
29
+ z.object({
30
+ id: z.string(),
31
+ question: z.string(),
32
+ options: z.array(z.string()),
33
+ recommendedAnswer: z.string().describe('The letter of the recommended option (e.g., "a", "b", "c")'),
34
+ justification: z.string().describe('Brief explanation for the recommended answer'),
35
+ })
36
+ ),
37
+ });
64
38
 
65
39
  export interface StructuredExtractor {
66
40
  extractQuestions(researchContent: string): Promise<ExtractedQuestion[]>;
67
41
  extractQuestionsWithAnswers(researchContent: string): Promise<ExtractedQuestionWithAnswer[]>;
68
42
  }
69
43
 
70
- export class OpenAIExtractor implements StructuredExtractor {
71
- private client: OpenAI;
44
+ export class AISDKExtractor implements StructuredExtractor {
72
45
  private logger: Logger;
46
+ private model: any;
73
47
 
74
48
  constructor(logger?: Logger) {
75
- const apiKey = process.env.OPENAI_API_KEY;
49
+ this.logger = logger || new Logger({ debug: false, prefix: '[AISDKExtractor]' });
50
+
51
+ // Determine which provider to use based on environment variables
52
+ // Priority: Anthropic (if ANTHROPIC_BASE_URL is set) > OpenAI
53
+ const apiKey = process.env.ANTHROPIC_AUTH_TOKEN
54
+ || process.env.ANTHROPIC_API_KEY
55
+ || process.env.OPENAI_API_KEY;
56
+
76
57
  if (!apiKey) {
77
- throw new Error('OPENAI_API_KEY environment variable is required for structured extraction');
58
+ throw new Error('Missing API key for structured extraction. Ensure the LLM gateway is configured.');
78
59
  }
79
-
80
- this.client = new OpenAI({ apiKey });
81
- this.logger = logger || new Logger({ debug: false, prefix: '[OpenAIExtractor]' });
60
+
61
+ const baseURL = process.env.ANTHROPIC_BASE_URL || process.env.OPENAI_BASE_URL;
62
+ const modelName = 'claude-haiku-4-5';
63
+ this.model = anthropic(modelName);
64
+ this.logger.debug('Using Anthropic provider for structured extraction', { modelName, baseURL });
82
65
  }
83
66
 
84
67
  async extractQuestions(researchContent: string): Promise<ExtractedQuestion[]> {
@@ -86,40 +69,20 @@ export class OpenAIExtractor implements StructuredExtractor {
86
69
  contentLength: researchContent.length,
87
70
  });
88
71
 
89
- const completion = await this.client.chat.completions.create({
90
- model: 'gpt-4o-mini',
91
- messages: [
92
- {
93
- role: 'system',
94
- content: 'Extract the research questions from the provided markdown. Return a JSON object matching the schema.',
95
- },
96
- {
97
- role: 'user',
98
- content: researchContent,
99
- },
100
- ],
101
- response_format: {
102
- type: 'json_schema',
103
- json_schema: {
104
- name: 'questions',
105
- strict: true,
106
- schema: questionsOnlySchema,
107
- },
108
- },
72
+ const { object } = await generateObject({
73
+ model: this.model,
74
+ schema: questionsOnlySchema,
75
+ schemaName: 'ResearchQuestions',
76
+ schemaDescription: 'Research questions extracted from markdown content',
77
+ system: 'Extract the research questions from the provided markdown. Return a JSON object matching the schema.',
78
+ prompt: researchContent,
109
79
  });
110
80
 
111
- const content = completion.choices[0].message.content;
112
- if (!content) {
113
- throw new Error('No content in OpenAI response');
114
- }
115
-
116
- const parsed = JSON.parse(content) as { questions: ExtractedQuestion[] };
117
-
118
81
  this.logger.info('Successfully extracted questions', {
119
- questionCount: parsed.questions.length,
82
+ questionCount: object.questions.length,
120
83
  });
121
84
 
122
- return parsed.questions;
85
+ return object.questions;
123
86
  }
124
87
 
125
88
  async extractQuestionsWithAnswers(
@@ -129,39 +92,19 @@ export class OpenAIExtractor implements StructuredExtractor {
129
92
  contentLength: researchContent.length,
130
93
  });
131
94
 
132
- const completion = await this.client.chat.completions.create({
133
- model: 'gpt-4o-mini',
134
- messages: [
135
- {
136
- role: 'system',
137
- content: 'Extract the research questions from the markdown and provide recommended answers based on the analysis. For each question, include a recommendedAnswer (the letter: a, b, c, etc.) and a brief justification. Return a JSON object matching the schema.',
138
- },
139
- {
140
- role: 'user',
141
- content: researchContent,
142
- },
143
- ],
144
- response_format: {
145
- type: 'json_schema',
146
- json_schema: {
147
- name: 'questions_with_answers',
148
- strict: true,
149
- schema: questionsWithAnswersSchema,
150
- },
151
- },
95
+ const { object } = await generateObject({
96
+ model: this.model,
97
+ schema: questionsWithAnswersSchema,
98
+ schemaName: 'ResearchQuestionsWithAnswers',
99
+ schemaDescription: 'Research questions with recommended answers extracted from markdown',
100
+ system: 'Extract the research questions from the markdown and provide recommended answers based on the analysis. For each question, include a recommendedAnswer (the letter: a, b, c, etc.) and a brief justification. Return a JSON object matching the schema.',
101
+ prompt: researchContent,
152
102
  });
153
103
 
154
- const content = completion.choices[0].message.content;
155
- if (!content) {
156
- throw new Error('No content in OpenAI response');
157
- }
158
-
159
- const parsed = JSON.parse(content) as { questions: ExtractedQuestionWithAnswer[] };
160
-
161
104
  this.logger.info('Successfully extracted questions with answers', {
162
- questionCount: parsed.questions.length,
105
+ questionCount: object.questions.length,
163
106
  });
164
107
 
165
- return parsed.questions;
108
+ return object.questions;
166
109
  }
167
110
  }
@@ -0,0 +1,42 @@
1
+ import type { WorkflowDefinition } from './types.js';
2
+ import { researchStep } from './steps/research.js';
3
+ import { planStep } from './steps/plan.js';
4
+ import { buildStep } from './steps/build.js';
5
+
6
+ const MODELS = {
7
+ SONNET: "claude-sonnet-4-5",
8
+ HAIKU: "claude-haiku-4-5",
9
+ }
10
+
11
+ export const TASK_WORKFLOW: WorkflowDefinition = [
12
+ {
13
+ id: 'research',
14
+ name: 'Research',
15
+ agent: 'research',
16
+ model: MODELS.HAIKU,
17
+ permissionMode: 'plan',
18
+ commit: true,
19
+ push: true,
20
+ run: researchStep,
21
+ },
22
+ {
23
+ id: 'plan',
24
+ name: 'Plan',
25
+ agent: 'planning',
26
+ model: MODELS.SONNET,
27
+ permissionMode: 'plan',
28
+ commit: true,
29
+ push: true,
30
+ run: planStep,
31
+ },
32
+ {
33
+ id: 'build',
34
+ name: 'Build',
35
+ agent: 'execution',
36
+ model: MODELS.SONNET,
37
+ permissionMode: 'acceptEdits',
38
+ commit: true,
39
+ push: true,
40
+ run: buildStep,
41
+ },
42
+ ];
@@ -0,0 +1,87 @@
1
+ import { query } from '@anthropic-ai/claude-agent-sdk';
2
+ import { EXECUTION_SYSTEM_PROMPT } from '../../agents/execution.js';
3
+ import { PermissionMode } from '../../types.js';
4
+ import type { WorkflowStepRunner } from '../types.js';
5
+ import { finalizeStepGitActions } from '../utils.js';
6
+
7
+ export const buildStep: WorkflowStepRunner = async ({ step, context }) => {
8
+ const {
9
+ task,
10
+ cwd,
11
+ options,
12
+ logger,
13
+ promptBuilder,
14
+ adapter,
15
+ mcpServers,
16
+ gitManager,
17
+ emitEvent,
18
+ } = context;
19
+
20
+ const stepLogger = logger.child('BuildStep');
21
+
22
+ const latestRun = task.latest_run;
23
+ const prExists =
24
+ latestRun?.output && typeof latestRun.output === 'object'
25
+ ? (latestRun.output as any).pr_url
26
+ : null;
27
+
28
+ if (prExists) {
29
+ stepLogger.info('PR already exists, skipping build phase', { taskId: task.id });
30
+ return { status: 'skipped' };
31
+ }
32
+
33
+ stepLogger.info('Starting build phase', { taskId: task.id });
34
+ emitEvent(adapter.createStatusEvent('phase_start', { phase: 'build' }));
35
+
36
+ const executionPrompt = await promptBuilder.buildExecutionPrompt(task, cwd);
37
+ const fullPrompt = `${EXECUTION_SYSTEM_PROMPT}\n\n${executionPrompt}`;
38
+
39
+ const configuredPermissionMode =
40
+ options.permissionMode ??
41
+ (typeof step.permissionMode === 'string'
42
+ ? (step.permissionMode as PermissionMode)
43
+ : step.permissionMode) ??
44
+ PermissionMode.ACCEPT_EDITS;
45
+
46
+ const baseOptions: Record<string, any> = {
47
+ model: step.model,
48
+ cwd,
49
+ permissionMode: configuredPermissionMode,
50
+ settingSources: ['local'],
51
+ mcpServers,
52
+ };
53
+
54
+ const response = query({
55
+ prompt: fullPrompt,
56
+ options: { ...baseOptions, ...(options.queryOverrides || {}) },
57
+ });
58
+
59
+ for await (const message of response) {
60
+ emitEvent(adapter.createRawSDKEvent(message));
61
+ const transformed = adapter.transform(message);
62
+ if (transformed) {
63
+ emitEvent(transformed);
64
+ }
65
+ }
66
+
67
+ const hasChanges = await gitManager.hasChanges();
68
+ context.stepResults[step.id] = { commitCreated: false };
69
+ if (!hasChanges) {
70
+ stepLogger.warn('No changes to commit in build phase', { taskId: task.id });
71
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'build' }));
72
+ return { status: 'completed' };
73
+ }
74
+
75
+ await gitManager.addFiles(['.']);
76
+ const commitCreated = await finalizeStepGitActions(context, step, {
77
+ commitMessage: `Implementation for ${task.title}`,
78
+ });
79
+ context.stepResults[step.id] = { commitCreated };
80
+
81
+ if (!commitCreated) {
82
+ stepLogger.warn('No commit created during build step', { taskId: task.id });
83
+ }
84
+
85
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'build' }));
86
+ return { status: 'completed' };
87
+ };
@@ -0,0 +1,112 @@
1
+ import { query } from '@anthropic-ai/claude-agent-sdk';
2
+ import { PLANNING_SYSTEM_PROMPT } from '../../agents/planning.js';
3
+ import type { WorkflowStepRunner } from '../types.js';
4
+ import { finalizeStepGitActions } from '../utils.js';
5
+
6
+ export const planStep: WorkflowStepRunner = async ({ step, context }) => {
7
+ const {
8
+ task,
9
+ cwd,
10
+ isCloudMode,
11
+ options,
12
+ logger,
13
+ fileManager,
14
+ gitManager,
15
+ promptBuilder,
16
+ adapter,
17
+ mcpServers,
18
+ emitEvent,
19
+ } = context;
20
+
21
+ const stepLogger = logger.child('PlanStep');
22
+
23
+ const existingPlan = await fileManager.readPlan(task.id);
24
+ if (existingPlan) {
25
+ stepLogger.info('Plan already exists, skipping step', { taskId: task.id });
26
+ return { status: 'skipped' };
27
+ }
28
+
29
+ const questionsData = await fileManager.readQuestions(task.id);
30
+ if (!questionsData || !questionsData.answered) {
31
+ stepLogger.info('Waiting for answered research questions', { taskId: task.id });
32
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
33
+ return { status: 'skipped', halt: true };
34
+ }
35
+
36
+ stepLogger.info('Starting planning phase', { taskId: task.id });
37
+ emitEvent(adapter.createStatusEvent('phase_start', { phase: 'planning' }));
38
+
39
+ const researchContent = await fileManager.readResearch(task.id);
40
+ let researchContext = '';
41
+ if (researchContent) {
42
+ researchContext += `## Research Analysis\n\n${researchContent}\n\n`;
43
+ }
44
+
45
+ researchContext += `## Implementation Decisions\n\n`;
46
+ for (const question of questionsData.questions) {
47
+ const answer = questionsData.answers?.find(
48
+ (a: any) => a.questionId === question.id
49
+ );
50
+
51
+ researchContext += `### ${question.question}\n\n`;
52
+ if (answer) {
53
+ researchContext += `**Selected:** ${answer.selectedOption}\n`;
54
+ if (answer.customInput) {
55
+ researchContext += `**Details:** ${answer.customInput}\n`;
56
+ }
57
+ } else {
58
+ researchContext += `**Selected:** Not answered\n`;
59
+ }
60
+ researchContext += `\n`;
61
+ }
62
+
63
+ const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);
64
+ const fullPrompt = `${PLANNING_SYSTEM_PROMPT}\n\n${planningPrompt}\n\n${researchContext}`;
65
+
66
+ const baseOptions: Record<string, any> = {
67
+ model: step.model,
68
+ cwd,
69
+ permissionMode: 'plan',
70
+ settingSources: ['local'],
71
+ mcpServers,
72
+ };
73
+
74
+ const response = query({
75
+ prompt: fullPrompt,
76
+ options: { ...baseOptions, ...(options.queryOverrides || {}) },
77
+ });
78
+
79
+ let planContent = '';
80
+ for await (const message of response) {
81
+ emitEvent(adapter.createRawSDKEvent(message));
82
+ const transformed = adapter.transform(message);
83
+ if (transformed) {
84
+ emitEvent(transformed);
85
+ }
86
+ if (message.type === 'assistant' && message.message?.content) {
87
+ for (const c of message.message.content) {
88
+ if (c.type === 'text' && c.text) {
89
+ planContent += `${c.text}\n`;
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ if (planContent.trim()) {
96
+ await fileManager.writePlan(task.id, planContent.trim());
97
+ stepLogger.info('Plan completed', { taskId: task.id });
98
+ }
99
+
100
+ await gitManager.addAllPostHogFiles();
101
+ await finalizeStepGitActions(context, step, {
102
+ commitMessage: `Planning phase for ${task.title}`,
103
+ });
104
+
105
+ if (!isCloudMode) {
106
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'planning' }));
107
+ return { status: 'completed', halt: true };
108
+ }
109
+
110
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'planning' }));
111
+ return { status: 'completed' };
112
+ };
@@ -0,0 +1,156 @@
1
+ import { query } from '@anthropic-ai/claude-agent-sdk';
2
+ import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
3
+ import type { ExtractedQuestionWithAnswer } from '../../structured-extraction.js';
4
+ import type { WorkflowStepRunner } from '../types.js';
5
+ import { finalizeStepGitActions } from '../utils.js';
6
+
7
+ export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
8
+ const {
9
+ task,
10
+ cwd,
11
+ isCloudMode,
12
+ options,
13
+ logger,
14
+ fileManager,
15
+ gitManager,
16
+ promptBuilder,
17
+ adapter,
18
+ mcpServers,
19
+ extractor,
20
+ emitEvent,
21
+ } = context;
22
+
23
+ const stepLogger = logger.child('ResearchStep');
24
+
25
+ const existingResearch = await fileManager.readResearch(task.id);
26
+ if (existingResearch) {
27
+ stepLogger.info('Research already exists, skipping step', { taskId: task.id });
28
+ return { status: 'skipped' };
29
+ }
30
+
31
+ stepLogger.info('Starting research phase', { taskId: task.id });
32
+ emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));
33
+
34
+ const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
35
+ const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
36
+
37
+ const baseOptions: Record<string, any> = {
38
+ model: step.model,
39
+ cwd,
40
+ permissionMode: 'plan',
41
+ settingSources: ['local'],
42
+ mcpServers,
43
+ };
44
+
45
+ const response = query({
46
+ prompt: fullPrompt,
47
+ options: { ...baseOptions, ...(options.queryOverrides || {}) },
48
+ });
49
+
50
+ let researchContent = '';
51
+ for await (const message of response) {
52
+ emitEvent(adapter.createRawSDKEvent(message));
53
+ const transformed = adapter.transform(message);
54
+ if (transformed) {
55
+ emitEvent(transformed);
56
+ }
57
+ if (message.type === 'assistant' && message.message?.content) {
58
+ for (const c of message.message.content) {
59
+ if (c.type === 'text' && c.text) {
60
+ researchContent += `${c.text}\n`;
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ if (researchContent.trim()) {
67
+ await fileManager.writeResearch(task.id, researchContent.trim());
68
+ stepLogger.info('Research completed', { taskId: task.id });
69
+ }
70
+
71
+ await gitManager.addAllPostHogFiles();
72
+ await finalizeStepGitActions(context, step, {
73
+ commitMessage: `Research phase for ${task.title}`,
74
+ });
75
+
76
+ if (extractor && researchContent.trim()) {
77
+ try {
78
+ stepLogger.info('Extracting questions from research.md', { taskId: task.id });
79
+ const parsedQuestions = await extractor.extractQuestions(researchContent);
80
+
81
+ await fileManager.writeQuestions(task.id, {
82
+ questions: parsedQuestions,
83
+ answered: false,
84
+ answers: null,
85
+ });
86
+
87
+ emitEvent({
88
+ type: 'artifact',
89
+ ts: Date.now(),
90
+ kind: 'research_questions',
91
+ content: parsedQuestions,
92
+ });
93
+
94
+ stepLogger.info('Questions extracted successfully', {
95
+ taskId: task.id,
96
+ count: parsedQuestions.length,
97
+ });
98
+ } catch (error) {
99
+ stepLogger.error('Failed to extract questions', {
100
+ taskId: task.id,
101
+ error: error instanceof Error ? error.message : String(error),
102
+ });
103
+ emitEvent({
104
+ type: 'error',
105
+ ts: Date.now(),
106
+ message: `Failed to extract questions: ${
107
+ error instanceof Error ? error.message : String(error)
108
+ }`,
109
+ });
110
+ }
111
+ } else if (!extractor) {
112
+ stepLogger.warn(
113
+ 'Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.'
114
+ );
115
+ emitEvent({
116
+ type: 'status',
117
+ ts: Date.now(),
118
+ phase: 'extraction_skipped',
119
+ message: 'Question extraction skipped - extractor not configured',
120
+ });
121
+ }
122
+
123
+ if (!isCloudMode) {
124
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
125
+ return { status: 'completed', halt: true };
126
+ }
127
+
128
+ const questionsData = await fileManager.readQuestions(task.id);
129
+ if (questionsData && !questionsData.answered && extractor && researchContent.trim()) {
130
+ const researchQuestions = await extractor.extractQuestionsWithAnswers(researchContent);
131
+ const answers = (researchQuestions as ExtractedQuestionWithAnswer[]).map((qa) => ({
132
+ questionId: qa.id,
133
+ selectedOption: qa.recommendedAnswer,
134
+ customInput: qa.justification,
135
+ }));
136
+
137
+ await fileManager.writeQuestions(task.id, {
138
+ questions: researchQuestions.map((qa) => ({
139
+ id: qa.id,
140
+ question: qa.question,
141
+ options: qa.options,
142
+ })),
143
+ answered: true,
144
+ answers,
145
+ });
146
+
147
+ await gitManager.addAllPostHogFiles();
148
+ await finalizeStepGitActions(context, step, {
149
+ commitMessage: `Answer research questions for ${task.title}`,
150
+ });
151
+ stepLogger.info('Auto-answered research questions', { taskId: task.id });
152
+ }
153
+
154
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
155
+ return { status: 'completed' };
156
+ };
@@ -0,0 +1,53 @@
1
+ import type { Task, TaskExecutionOptions, PermissionMode } from '../types.js';
2
+ import type { Logger } from '../utils/logger.js';
3
+ import type { PostHogFileManager } from '../file-manager.js';
4
+ import type { GitManager } from '../git-manager.js';
5
+ import type { PromptBuilder } from '../prompt-builder.js';
6
+ import type { TaskProgressReporter } from '../task-progress-reporter.js';
7
+ import type { ProviderAdapter } from '../adapters/types.js';
8
+ import type { PostHogAPIClient } from '../posthog-api.js';
9
+ import type { StructuredExtractor } from '../structured-extraction.js';
10
+
11
+ export interface WorkflowRuntime {
12
+ task: Task;
13
+ taskSlug: string;
14
+ cwd: string;
15
+ isCloudMode: boolean;
16
+ options: TaskExecutionOptions;
17
+ logger: Logger;
18
+ fileManager: PostHogFileManager;
19
+ gitManager: GitManager;
20
+ promptBuilder: PromptBuilder;
21
+ progressReporter: TaskProgressReporter;
22
+ adapter: ProviderAdapter;
23
+ mcpServers?: Record<string, any>;
24
+ posthogAPI?: PostHogAPIClient;
25
+ extractor?: StructuredExtractor;
26
+ emitEvent: (event: any) => void;
27
+ stepResults: Record<string, any>;
28
+ }
29
+
30
+ export interface WorkflowStepDefinition {
31
+ id: string;
32
+ name: string;
33
+ agent: string;
34
+ model: string;
35
+ permissionMode?: PermissionMode | string;
36
+ commit?: boolean;
37
+ push?: boolean;
38
+ run: WorkflowStepRunner;
39
+ }
40
+
41
+ export interface WorkflowStepRuntime {
42
+ step: WorkflowStepDefinition;
43
+ context: WorkflowRuntime;
44
+ }
45
+
46
+ export interface WorkflowStepResult {
47
+ status: 'completed' | 'skipped';
48
+ halt?: boolean;
49
+ }
50
+
51
+ export type WorkflowStepRunner = (runtime: WorkflowStepRuntime) => Promise<WorkflowStepResult>;
52
+
53
+ export type WorkflowDefinition = WorkflowStepDefinition[];