@posthog/agent 1.16.6 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/index.d.ts +1 -3
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/src/agent.d.ts +0 -3
  4. package/dist/src/agent.d.ts.map +1 -1
  5. package/dist/src/agent.js +6 -27
  6. package/dist/src/agent.js.map +1 -1
  7. package/dist/src/agents/research.d.ts +1 -1
  8. package/dist/src/agents/research.d.ts.map +1 -1
  9. package/dist/src/agents/research.js +84 -53
  10. package/dist/src/agents/research.js.map +1 -1
  11. package/dist/src/file-manager.d.ts +3 -21
  12. package/dist/src/file-manager.d.ts.map +1 -1
  13. package/dist/src/file-manager.js +15 -47
  14. package/dist/src/file-manager.js.map +1 -1
  15. package/dist/src/git-manager.d.ts.map +1 -1
  16. package/dist/src/git-manager.js +8 -1
  17. package/dist/src/git-manager.js.map +1 -1
  18. package/dist/src/types.d.ts +20 -1
  19. package/dist/src/types.d.ts.map +1 -1
  20. package/dist/src/types.js.map +1 -1
  21. package/dist/src/workflow/steps/plan.d.ts.map +1 -1
  22. package/dist/src/workflow/steps/plan.js +26 -18
  23. package/dist/src/workflow/steps/plan.js.map +1 -1
  24. package/dist/src/workflow/steps/research.d.ts.map +1 -1
  25. package/dist/src/workflow/steps/research.js +100 -66
  26. package/dist/src/workflow/steps/research.js.map +1 -1
  27. package/dist/src/workflow/types.d.ts +0 -2
  28. package/dist/src/workflow/types.d.ts.map +1 -1
  29. package/dist/templates/plan-template.md +1 -5
  30. package/package.json +2 -6
  31. package/src/agent.ts +7 -31
  32. package/src/agents/research.ts +84 -53
  33. package/src/file-manager.ts +18 -73
  34. package/src/git-manager.ts +7 -1
  35. package/src/templates/plan-template.md +1 -5
  36. package/src/types.ts +24 -1
  37. package/src/workflow/steps/plan.ts +28 -21
  38. package/src/workflow/steps/research.ts +109 -74
  39. package/src/workflow/types.ts +0 -2
  40. package/dist/_virtual/_commonjsHelpers.js +0 -6
  41. package/dist/_virtual/_commonjsHelpers.js.map +0 -1
  42. package/dist/_virtual/index.js +0 -4
  43. package/dist/_virtual/index.js.map +0 -1
  44. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +0 -1154
  45. package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +0 -1
  46. package/dist/node_modules/@ai-sdk/provider/dist/index.js +0 -296
  47. package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +0 -1
  48. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +0 -576
  49. package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +0 -1
  50. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +0 -741
  51. package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +0 -1
  52. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +0 -112
  53. package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +0 -1
  54. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +0 -123
  55. package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +0 -1
  56. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +0 -62
  57. package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +0 -1
  58. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +0 -91
  59. package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +0 -1
  60. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +0 -79
  61. package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +0 -1
  62. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +0 -59
  63. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +0 -1
  64. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +0 -99
  65. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +0 -1
  66. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +0 -31
  67. package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +0 -1
  68. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +0 -69
  69. package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +0 -1
  70. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +0 -54
  71. package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +0 -1
  72. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +0 -22
  73. package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +0 -1
  74. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +0 -104
  75. package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +0 -1
  76. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +0 -44
  77. package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +0 -1
  78. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +0 -43
  79. package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +0 -1
  80. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +0 -27
  81. package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +0 -1
  82. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +0 -62
  83. package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +0 -1
  84. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +0 -121
  85. package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +0 -1
  86. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +0 -167
  87. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +0 -1
  88. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +0 -33
  89. package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +0 -1
  90. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +0 -22
  91. package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +0 -1
  92. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +0 -21
  93. package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +0 -1
  94. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +0 -35
  95. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +0 -1
  96. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +0 -40
  97. package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +0 -1
  98. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +0 -22
  99. package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +0 -1
  100. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +0 -70
  101. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +0 -1
  102. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +0 -78
  103. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +0 -1
  104. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +0 -34
  105. package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +0 -1
  106. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +0 -55
  107. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +0 -1
  108. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +0 -56
  109. package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +0 -1
  110. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +0 -76
  111. package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +0 -1
  112. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +0 -27
  113. package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +0 -1
  114. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +0 -45
  115. package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +0 -1
  116. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +0 -22
  117. package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +0 -1
  118. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +0 -25
  119. package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +0 -1
  120. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +0 -24
  121. package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +0 -1
  122. package/dist/node_modules/@opentelemetry/api/build/esm/version.js +0 -20
  123. package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +0 -1
  124. package/dist/node_modules/ai/dist/index.js +0 -2870
  125. package/dist/node_modules/ai/dist/index.js.map +0 -1
  126. package/dist/node_modules/nanoid/non-secure/index.js +0 -13
  127. package/dist/node_modules/nanoid/non-secure/index.js.map +0 -1
  128. package/dist/node_modules/secure-json-parse/index.js +0 -133
  129. package/dist/node_modules/secure-json-parse/index.js.map +0 -1
  130. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +0 -37
  131. package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +0 -1
  132. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +0 -26
  133. package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +0 -1
  134. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +0 -17
  135. package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +0 -1
  136. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +0 -11
  137. package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +0 -1
  138. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +0 -8
  139. package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +0 -1
  140. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +0 -66
  141. package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +0 -1
  142. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +0 -21
  143. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +0 -1
  144. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +0 -30
  145. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +0 -1
  146. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +0 -53
  147. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +0 -1
  148. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +0 -8
  149. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +0 -1
  150. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +0 -8
  151. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +0 -1
  152. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +0 -8
  153. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +0 -1
  154. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +0 -50
  155. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +0 -1
  156. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +0 -11
  157. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +0 -1
  158. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +0 -11
  159. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +0 -1
  160. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +0 -9
  161. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +0 -1
  162. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +0 -56
  163. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +0 -1
  164. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +0 -24
  165. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +0 -1
  166. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +0 -30
  167. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +0 -1
  168. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +0 -19
  169. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +0 -1
  170. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +0 -15
  171. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +0 -1
  172. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +0 -13
  173. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +0 -1
  174. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +0 -37
  175. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +0 -1
  176. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +0 -56
  177. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +0 -1
  178. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +0 -76
  179. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +0 -1
  180. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +0 -25
  181. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +0 -1
  182. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +0 -24
  183. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +0 -1
  184. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +0 -8
  185. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +0 -1
  186. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +0 -8
  187. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +0 -1
  188. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +0 -65
  189. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +0 -1
  190. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +0 -24
  191. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +0 -1
  192. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +0 -350
  193. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +0 -1
  194. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +0 -36
  195. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +0 -1
  196. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +0 -10
  197. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +0 -1
  198. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +0 -84
  199. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +0 -1
  200. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +0 -8
  201. package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +0 -1
  202. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +0 -110
  203. package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +0 -1
  204. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +0 -90
  205. package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +0 -1
  206. package/dist/src/structured-extraction.d.ts +0 -28
  207. package/dist/src/structured-extraction.d.ts.map +0 -1
  208. package/dist/src/structured-extraction.js +0 -77
  209. package/dist/src/structured-extraction.js.map +0 -1
  210. package/dist/src/utils/ai-sdk.d.ts +0 -14
  211. package/dist/src/utils/ai-sdk.d.ts.map +0 -1
  212. package/dist/src/utils/ai-sdk.js +0 -38
  213. package/dist/src/utils/ai-sdk.js.map +0 -1
  214. package/src/structured-extraction.ts +0 -117
  215. package/src/utils/ai-sdk.ts +0 -47
@@ -1,6 +1,6 @@
1
1
  import { promises as fs } from 'fs';
2
- import { join, dirname } from 'path';
3
- import type { SupportingFile } from './types.js';
2
+ import { join } from 'path';
3
+ import type { SupportingFile, ResearchEvaluation } from './types.js';
4
4
  import { Logger } from './utils/logger.js';
5
5
 
6
6
  export interface TaskFile {
@@ -9,24 +9,6 @@ export interface TaskFile {
9
9
  type: 'plan' | 'context' | 'reference' | 'output' | 'artifact';
10
10
  }
11
11
 
12
- export interface QuestionData {
13
- id: string;
14
- question: string;
15
- options: string[];
16
- }
17
-
18
- export interface AnswerData {
19
- questionId: string;
20
- selectedOption: string;
21
- customInput?: string;
22
- }
23
-
24
- export interface QuestionsFile {
25
- questions: QuestionData[];
26
- answered: boolean;
27
- answers: AnswerData[] | null;
28
- }
29
-
30
12
  export class PostHogFileManager {
31
13
  private repositoryPath: string;
32
14
  private logger: Logger;
@@ -170,48 +152,35 @@ export class PostHogFileManager {
170
152
  return await this.readTaskFile(taskId, 'requirements.md');
171
153
  }
172
154
 
173
- async writeResearch(taskId: string, content: string): Promise<void> {
155
+ async writeResearch(taskId: string, data: ResearchEvaluation): Promise<void> {
174
156
  this.logger.debug('Writing research', {
175
157
  taskId,
176
- contentLength: content.length,
177
- contentPreview: content.substring(0, 200)
158
+ score: data.actionabilityScore,
159
+ hasQuestions: !!data.questions,
160
+ questionCount: data.questions?.length ?? 0,
161
+ answered: data.answered ?? false,
178
162
  });
179
163
 
180
164
  await this.writeTaskFile(taskId, {
181
- name: 'research.md',
182
- content: content,
183
- type: 'artifact'
184
- });
185
-
186
- this.logger.info('Research file written', { taskId });
187
- }
188
-
189
- async readResearch(taskId: string): Promise<string | null> {
190
- return await this.readTaskFile(taskId, 'research.md');
191
- }
192
-
193
- async writeQuestions(taskId: string, data: QuestionsFile): Promise<void> {
194
- this.logger.debug('Writing questions', {
195
- taskId,
196
- questionCount: data.questions.length,
197
- answered: data.answered,
198
- });
199
-
200
- await this.writeTaskFile(taskId, {
201
- name: 'questions.json',
165
+ name: 'research.json',
202
166
  content: JSON.stringify(data, null, 2),
203
167
  type: 'artifact'
204
168
  });
205
169
 
206
- this.logger.info('Questions file written', { taskId });
170
+ this.logger.info('Research file written', {
171
+ taskId,
172
+ score: data.actionabilityScore,
173
+ hasQuestions: !!data.questions,
174
+ answered: data.answered ?? false,
175
+ });
207
176
  }
208
177
 
209
- async readQuestions(taskId: string): Promise<QuestionsFile | null> {
178
+ async readResearch(taskId: string): Promise<ResearchEvaluation | null> {
210
179
  try {
211
- const content = await this.readTaskFile(taskId, 'questions.json');
212
- return content ? JSON.parse(content) as QuestionsFile : null;
180
+ const content = await this.readTaskFile(taskId, 'research.json');
181
+ return content ? JSON.parse(content) as ResearchEvaluation : null;
213
182
  } catch (error) {
214
- this.logger.debug('Failed to parse questions.json', { error });
183
+ this.logger.debug('Failed to parse research.json', { error });
215
184
  return null;
216
185
  }
217
186
  }
@@ -241,28 +210,4 @@ export class PostHogFileManager {
241
210
 
242
211
  return files;
243
212
  }
244
-
245
- async ensureGitignore(): Promise<void> {
246
- const gitignorePath = join(this.repositoryPath, '.posthog', '.gitignore');
247
- const gitignoreContent = `# PostHog task artifacts - customize as needed
248
- # Exclude temporary files
249
- */temp/
250
- */cache/
251
- */.env
252
- */.secrets
253
-
254
- # Include plans and documentation by default
255
- !*/plan.md
256
- !*/context.md
257
- !*/requirements.md
258
- !*/README.md
259
- `;
260
-
261
- try {
262
- await fs.access(gitignorePath);
263
- } catch {
264
- await fs.mkdir(dirname(gitignorePath), { recursive: true });
265
- await fs.writeFile(gitignorePath, gitignoreContent, 'utf8');
266
- }
267
- }
268
213
  }
@@ -135,7 +135,13 @@ export class GitManager {
135
135
  }
136
136
 
137
137
  async addAllPostHogFiles(): Promise<void> {
138
- await this.runGitCommand('add .posthog/');
138
+ try {
139
+ // Use -A flag to add all changes (including new files) and ignore errors if directory is empty
140
+ await this.runGitCommand('add -A .posthog/');
141
+ } catch (error) {
142
+ // If the directory doesn't exist or has no files, that's fine - just log and continue
143
+ this.logger.debug('No PostHog files to add', { error });
144
+ }
139
145
  }
140
146
 
141
147
  async commitChanges(message: string, options?: {
@@ -38,8 +38,4 @@ path/to/existing/file.ts - Changes needed
38
38
 
39
39
  - Key architectural decisions
40
40
  - Potential risks and mitigation
41
- - Testing approach
42
-
43
- ---
44
-
45
- *Generated by PostHog Agent*
41
+ - Testing approach
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  // import and export to keep a single type file
3
- import type { CanUseTool, PermissionResult } from '@anthropic-ai/claude-agent-sdk/sdkTypes.js';
3
+ import type { CanUseTool, PermissionResult } from '@anthropic-ai/claude-agent-sdk';
4
4
  export type { CanUseTool, PermissionResult };
5
5
 
6
6
  // PostHog Task model (matches Array's OpenAPI schema)
@@ -345,4 +345,27 @@ export interface UrlMention {
345
345
  type: ResourceType;
346
346
  id?: string;
347
347
  label?: string;
348
+ }
349
+
350
+ // Research evaluation types
351
+ export interface ResearchQuestion {
352
+ id: string;
353
+ question: string;
354
+ options: string[];
355
+ }
356
+
357
+ export interface ResearchAnswer {
358
+ questionId: string;
359
+ selectedOption: string;
360
+ customInput?: string;
361
+ }
362
+
363
+ export interface ResearchEvaluation {
364
+ actionabilityScore: number; // 0-1 confidence score
365
+ context: string; // brief summary for planning
366
+ keyFiles: string[]; // files needing modification
367
+ blockers?: string[]; // what's preventing full confidence
368
+ questions?: ResearchQuestion[]; // only if score < 0.7
369
+ answered?: boolean; // whether questions have been answered
370
+ answers?: ResearchAnswer[]; // user's answers to questions
348
371
  }
@@ -26,8 +26,8 @@ export const planStep: WorkflowStepRunner = async ({ step, context }) => {
26
26
  return { status: 'skipped' };
27
27
  }
28
28
 
29
- const questionsData = await fileManager.readQuestions(task.id);
30
- if (!questionsData || !questionsData.answered) {
29
+ const researchData = await fileManager.readResearch(task.id);
30
+ if (researchData?.questions && !researchData.answered) {
31
31
  stepLogger.info('Waiting for answered research questions', { taskId: task.id });
32
32
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
33
33
  return { status: 'skipped', halt: true };
@@ -35,29 +35,36 @@ export const planStep: WorkflowStepRunner = async ({ step, context }) => {
35
35
 
36
36
  stepLogger.info('Starting planning phase', { taskId: task.id });
37
37
  emitEvent(adapter.createStatusEvent('phase_start', { phase: 'planning' }));
38
-
39
- const researchContent = await fileManager.readResearch(task.id);
40
38
  let researchContext = '';
41
- if (researchContent) {
42
- researchContext += `## Research Analysis\n\n${researchContent}\n\n`;
43
- }
44
-
45
- researchContext += `## Implementation Decisions\n\n`;
46
- for (const question of questionsData.questions) {
47
- const answer = questionsData.answers?.find(
48
- (a: any) => a.questionId === question.id
49
- );
39
+ if (researchData) {
40
+ researchContext += `## Research Context\n\n${researchData.context}\n\n`;
41
+ if (researchData.keyFiles.length > 0) {
42
+ researchContext += `**Key Files:**\n${researchData.keyFiles.map(f => `- ${f}`).join('\n')}\n\n`;
43
+ }
44
+ if (researchData.blockers && researchData.blockers.length > 0) {
45
+ researchContext += `**Considerations:**\n${researchData.blockers.map(b => `- ${b}`).join('\n')}\n\n`;
46
+ }
50
47
 
51
- researchContext += `### ${question.question}\n\n`;
52
- if (answer) {
53
- researchContext += `**Selected:** ${answer.selectedOption}\n`;
54
- if (answer.customInput) {
55
- researchContext += `**Details:** ${answer.customInput}\n`;
48
+ // Add answered questions if they exist
49
+ if (researchData.questions && researchData.answers && researchData.answered) {
50
+ researchContext += `## Implementation Decisions\n\n`;
51
+ for (const question of researchData.questions) {
52
+ const answer = researchData.answers.find(
53
+ (a) => a.questionId === question.id
54
+ );
55
+
56
+ researchContext += `### ${question.question}\n\n`;
57
+ if (answer) {
58
+ researchContext += `**Selected:** ${answer.selectedOption}\n`;
59
+ if (answer.customInput) {
60
+ researchContext += `**Details:** ${answer.customInput}\n`;
61
+ }
62
+ } else {
63
+ researchContext += `**Selected:** Not answered\n`;
64
+ }
65
+ researchContext += `\n`;
56
66
  }
57
- } else {
58
- researchContext += `**Selected:** Not answered\n`;
59
67
  }
60
- researchContext += `\n`;
61
68
  }
62
69
 
63
70
  const planningPrompt = await promptBuilder.buildPlanningPrompt(task, cwd);
@@ -1,7 +1,7 @@
1
1
  import { query } from '@anthropic-ai/claude-agent-sdk';
2
2
  import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
3
- import type { ExtractedQuestionWithAnswer } from '../../structured-extraction.js';
4
3
  import type { WorkflowStepRunner } from '../types.js';
4
+ import type { ResearchEvaluation } from '../../types.js';
5
5
  import { finalizeStepGitActions } from '../utils.js';
6
6
 
7
7
  export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
@@ -16,7 +16,6 @@ export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
16
16
  promptBuilder,
17
17
  adapter,
18
18
  mcpServers,
19
- extractor,
20
19
  emitEvent,
21
20
  } = context;
22
21
 
@@ -24,7 +23,29 @@ export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
24
23
 
25
24
  const existingResearch = await fileManager.readResearch(task.id);
26
25
  if (existingResearch) {
27
- stepLogger.info('Research already exists, skipping step', { taskId: task.id });
26
+ stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });
27
+
28
+ // If there are unanswered questions, re-emit them so UI can prompt user
29
+ if (existingResearch.questions && !existingResearch.answered) {
30
+ stepLogger.info('Re-emitting unanswered research questions', {
31
+ taskId: task.id,
32
+ questionCount: existingResearch.questions.length
33
+ });
34
+
35
+ emitEvent({
36
+ type: 'artifact',
37
+ ts: Date.now(),
38
+ kind: 'research_questions',
39
+ content: existingResearch.questions,
40
+ });
41
+
42
+ // In local mode, halt to allow user to answer
43
+ if (!isCloudMode) {
44
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
45
+ return { status: 'skipped', halt: true };
46
+ }
47
+ }
48
+
28
49
  return { status: 'skipped' };
29
50
  }
30
51
 
@@ -59,7 +80,7 @@ export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
59
80
  options: { ...baseOptions, ...(options.queryOverrides || {}) },
60
81
  });
61
82
 
62
- let researchContent = '';
83
+ let jsonContent = '';
63
84
  for await (const message of response) {
64
85
  emitEvent(adapter.createRawSDKEvent(message));
65
86
  const transformed = adapter.transform(message);
@@ -69,100 +90,114 @@ export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
69
90
  if (message.type === 'assistant' && message.message?.content) {
70
91
  for (const c of message.message.content) {
71
92
  if (c.type === 'text' && c.text) {
72
- researchContent += `${c.text}\n`;
93
+ jsonContent += c.text;
73
94
  }
74
95
  }
75
96
  }
76
97
  }
77
98
 
78
- if (researchContent.trim()) {
79
- await fileManager.writeResearch(task.id, researchContent.trim());
80
- stepLogger.info('Research completed', { taskId: task.id });
99
+ if (!jsonContent.trim()) {
100
+ stepLogger.error('No JSON output from research agent', { taskId: task.id });
101
+ emitEvent({
102
+ type: 'error',
103
+ ts: Date.now(),
104
+ message: 'Research agent returned no output',
105
+ });
106
+ return { status: 'completed', halt: true };
107
+ }
108
+
109
+ // Parse JSON response
110
+ let evaluation: ResearchEvaluation;
111
+ try {
112
+ // Extract JSON from potential markdown code blocks or other wrapping
113
+ const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
114
+ if (!jsonMatch) {
115
+ throw new Error('No JSON object found in response');
116
+ }
117
+ evaluation = JSON.parse(jsonMatch[0]);
118
+ stepLogger.info('Parsed research evaluation', {
119
+ taskId: task.id,
120
+ score: evaluation.actionabilityScore,
121
+ hasQuestions: !!evaluation.questions,
122
+ });
123
+ } catch (error) {
124
+ stepLogger.error('Failed to parse research JSON', {
125
+ taskId: task.id,
126
+ error: error instanceof Error ? error.message : String(error),
127
+ content: jsonContent.substring(0, 500),
128
+ });
129
+ emitEvent({
130
+ type: 'error',
131
+ ts: Date.now(),
132
+ message: `Failed to parse research JSON: ${
133
+ error instanceof Error ? error.message : String(error)
134
+ }`,
135
+ });
136
+ return { status: 'completed', halt: true };
137
+ }
138
+
139
+ // Add answered/answers fields to evaluation
140
+ if (evaluation.questions && evaluation.questions.length > 0) {
141
+ evaluation.answered = false;
142
+ evaluation.answers = undefined;
81
143
  }
82
144
 
145
+ // Always write research.json
146
+ await fileManager.writeResearch(task.id, evaluation);
147
+ stepLogger.info('Research evaluation written', {
148
+ taskId: task.id,
149
+ score: evaluation.actionabilityScore,
150
+ hasQuestions: !!evaluation.questions,
151
+ });
152
+
153
+ emitEvent({
154
+ type: 'artifact',
155
+ ts: Date.now(),
156
+ kind: 'research_evaluation',
157
+ content: evaluation,
158
+ });
159
+
83
160
  await gitManager.addAllPostHogFiles();
84
161
  await finalizeStepGitActions(context, step, {
85
162
  commitMessage: `Research phase for ${task.title}`,
86
163
  });
87
164
 
88
- if (extractor && researchContent.trim()) {
89
- try {
90
- stepLogger.info('Extracting questions from research.md', { taskId: task.id });
91
- const parsedQuestions = await extractor.extractQuestions(researchContent);
92
-
93
- await fileManager.writeQuestions(task.id, {
94
- questions: parsedQuestions,
95
- answered: false,
96
- answers: null,
97
- });
98
-
99
- emitEvent({
100
- type: 'artifact',
101
- ts: Date.now(),
102
- kind: 'research_questions',
103
- content: parsedQuestions,
104
- });
105
-
106
- stepLogger.info('Questions extracted successfully', {
107
- taskId: task.id,
108
- count: parsedQuestions.length,
109
- });
110
- } catch (error) {
111
- stepLogger.error('Failed to extract questions', {
112
- taskId: task.id,
113
- error: error instanceof Error ? error.message : String(error),
114
- });
115
- emitEvent({
116
- type: 'error',
117
- ts: Date.now(),
118
- message: `Failed to extract questions: ${
119
- error instanceof Error ? error.message : String(error)
120
- }`,
121
- });
122
- }
123
- } else if (!extractor) {
124
- stepLogger.warn(
125
- 'Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.'
126
- );
165
+ // Log whether questions need answering
166
+ if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {
167
+ stepLogger.info('Actionability score below threshold, questions needed', {
168
+ taskId: task.id,
169
+ score: evaluation.actionabilityScore,
170
+ questionCount: evaluation.questions.length,
171
+ });
172
+
127
173
  emitEvent({
128
- type: 'status',
174
+ type: 'artifact',
129
175
  ts: Date.now(),
130
- phase: 'extraction_skipped',
131
- message: 'Question extraction skipped - extractor not configured',
176
+ kind: 'research_questions',
177
+ content: evaluation.questions,
178
+ });
179
+ } else {
180
+ stepLogger.info('Actionability score acceptable, proceeding to planning', {
181
+ taskId: task.id,
182
+ score: evaluation.actionabilityScore,
132
183
  });
133
184
  }
134
185
 
186
+ // In local mode, always halt after research for user review
135
187
  if (!isCloudMode) {
136
188
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
137
189
  return { status: 'completed', halt: true };
138
190
  }
139
191
 
140
- const questionsData = await fileManager.readQuestions(task.id);
141
- if (questionsData && !questionsData.answered && extractor && researchContent.trim()) {
142
- const researchQuestions = await extractor.extractQuestionsWithAnswers(researchContent);
143
- const answers = (researchQuestions as ExtractedQuestionWithAnswer[]).map((qa) => ({
144
- questionId: qa.id,
145
- selectedOption: qa.recommendedAnswer,
146
- customInput: qa.justification,
147
- }));
148
-
149
- await fileManager.writeQuestions(task.id, {
150
- questions: researchQuestions.map((qa) => ({
151
- id: qa.id,
152
- question: qa.question,
153
- options: qa.options,
154
- })),
155
- answered: true,
156
- answers,
157
- });
158
-
159
- await gitManager.addAllPostHogFiles();
160
- await finalizeStepGitActions(context, step, {
161
- commitMessage: `Answer research questions for ${task.title}`,
162
- });
163
- stepLogger.info('Auto-answered research questions', { taskId: task.id });
192
+ // In cloud mode, check if questions need answering
193
+ const researchData = await fileManager.readResearch(task.id);
194
+ if (researchData?.questions && !researchData.answered) {
195
+ // Questions need answering - halt for user input in cloud mode too
196
+ emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
197
+ return { status: 'completed', halt: true };
164
198
  }
165
199
 
200
+ // No questions or questions already answered - proceed to planning
166
201
  emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
167
202
  return { status: 'completed' };
168
203
  };
@@ -6,7 +6,6 @@ import type { PromptBuilder } from '../prompt-builder.js';
6
6
  import type { TaskProgressReporter } from '../task-progress-reporter.js';
7
7
  import type { ProviderAdapter } from '../adapters/types.js';
8
8
  import type { PostHogAPIClient } from '../posthog-api.js';
9
- import type { StructuredExtractor } from '../structured-extraction.js';
10
9
 
11
10
  export interface WorkflowRuntime {
12
11
  task: Task;
@@ -22,7 +21,6 @@ export interface WorkflowRuntime {
22
21
  adapter: ProviderAdapter;
23
22
  mcpServers?: Record<string, any>;
24
23
  posthogAPI?: PostHogAPIClient;
25
- extractor?: StructuredExtractor;
26
24
  emitEvent: (event: any) => void;
27
25
  stepResults: Record<string, any>;
28
26
  }
@@ -1,6 +0,0 @@
1
- function getDefaultExportFromCjs (x) {
2
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
3
- }
4
-
5
- export { getDefaultExportFromCjs };
6
- //# sourceMappingURL=_commonjsHelpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_commonjsHelpers.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -1,4 +0,0 @@
1
- var secureJsonParse = {exports: {}};
2
-
3
- export { secureJsonParse as __module };
4
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}