@posthog/agent 2.1.59 → 2.1.62

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/agent",
3
- "version": "2.1.59",
3
+ "version": "2.1.62",
4
4
  "repository": "https://github.com/PostHog/twig",
5
5
  "description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
6
6
  "exports": {
@@ -47,6 +47,7 @@ type ChunkHandlerContext = {
47
47
  fileContentCache: { [key: string]: string };
48
48
  client: AgentSideConnection;
49
49
  logger: Logger;
50
+ parentToolCallId?: string;
50
51
  };
51
52
 
52
53
  export interface MessageHandlerContext {
@@ -62,20 +63,34 @@ function messageUpdateType(role: Role) {
62
63
  return role === "assistant" ? "agent_message_chunk" : "user_message_chunk";
63
64
  }
64
65
 
65
- function toolMeta(toolName: string, toolResponse?: unknown): ToolUpdateMeta {
66
- return toolResponse
67
- ? { claudeCode: { toolName, toolResponse } }
68
- : { claudeCode: { toolName } };
66
+ function toolMeta(
67
+ toolName: string,
68
+ toolResponse?: unknown,
69
+ parentToolCallId?: string,
70
+ ): ToolUpdateMeta {
71
+ const meta: ToolUpdateMeta["claudeCode"] = { toolName };
72
+ if (toolResponse !== undefined) meta.toolResponse = toolResponse;
73
+ if (parentToolCallId) meta.parentToolCallId = parentToolCallId;
74
+ return { claudeCode: meta };
69
75
  }
70
76
 
71
77
  function handleTextChunk(
72
78
  chunk: { text: string },
73
79
  role: Role,
80
+ parentToolCallId?: string,
74
81
  ): SessionNotification["update"] {
75
- return {
82
+ const update: SessionNotification["update"] = {
76
83
  sessionUpdate: messageUpdateType(role),
77
84
  content: text(chunk.text),
78
85
  };
86
+ if (parentToolCallId) {
87
+ (update as Record<string, unknown>)._meta = toolMeta(
88
+ "__text__",
89
+ undefined,
90
+ parentToolCallId,
91
+ );
92
+ }
93
+ return update;
79
94
  }
80
95
 
81
96
  function handleImageChunk(
@@ -94,13 +109,22 @@ function handleImageChunk(
94
109
  };
95
110
  }
96
111
 
97
- function handleThinkingChunk(chunk: {
98
- thinking: string;
99
- }): SessionNotification["update"] {
100
- return {
112
+ function handleThinkingChunk(
113
+ chunk: { thinking: string },
114
+ parentToolCallId?: string,
115
+ ): SessionNotification["update"] {
116
+ const update: SessionNotification["update"] = {
101
117
  sessionUpdate: "agent_thought_chunk",
102
118
  content: text(chunk.thinking),
103
119
  };
120
+ if (parentToolCallId) {
121
+ (update as Record<string, unknown>)._meta = toolMeta(
122
+ "__thinking__",
123
+ undefined,
124
+ parentToolCallId,
125
+ );
126
+ }
127
+ return update;
104
128
  }
105
129
 
106
130
  function handleToolUseChunk(
@@ -127,7 +151,7 @@ function handleToolUseChunk(
127
151
  await ctx.client.sessionUpdate({
128
152
  sessionId: ctx.sessionId,
129
153
  update: {
130
- _meta: toolMeta(toolUse.name, toolResponse),
154
+ _meta: toolMeta(toolUse.name, toolResponse, ctx.parentToolCallId),
131
155
  toolCallId: toolUseId,
132
156
  sessionUpdate: "tool_call_update",
133
157
  },
@@ -148,7 +172,7 @@ function handleToolUseChunk(
148
172
  }
149
173
 
150
174
  return {
151
- _meta: toolMeta(chunk.name),
175
+ _meta: toolMeta(chunk.name, undefined, ctx.parentToolCallId),
152
176
  toolCallId: chunk.id,
153
177
  sessionUpdate: "tool_call",
154
178
  rawInput,
@@ -174,7 +198,7 @@ function handleToolResultChunk(
174
198
  }
175
199
 
176
200
  return {
177
- _meta: toolMeta(toolUse.name),
201
+ _meta: toolMeta(toolUse.name, undefined, ctx.parentToolCallId),
178
202
  toolCallId: chunk.tool_use_id,
179
203
  sessionUpdate: "tool_call_update",
180
204
  status: chunk.is_error ? "failed" : "completed",
@@ -193,14 +217,14 @@ function processContentChunk(
193
217
  switch (chunk.type) {
194
218
  case "text":
195
219
  case "text_delta":
196
- return handleTextChunk(chunk, role);
220
+ return handleTextChunk(chunk, role, ctx.parentToolCallId);
197
221
 
198
222
  case "image":
199
223
  return handleImageChunk(chunk, role);
200
224
 
201
225
  case "thinking":
202
226
  case "thinking_delta":
203
- return handleThinkingChunk(chunk);
227
+ return handleThinkingChunk(chunk, ctx.parentToolCallId);
204
228
 
205
229
  case "tool_use":
206
230
  case "server_tool_use":
@@ -250,17 +274,21 @@ function toAcpNotifications(
250
274
  fileContentCache: { [key: string]: string },
251
275
  client: AgentSideConnection,
252
276
  logger: Logger,
277
+ parentToolCallId?: string,
253
278
  ): SessionNotification[] {
254
279
  if (typeof content === "string") {
255
- return [
256
- {
257
- sessionId,
258
- update: {
259
- sessionUpdate: messageUpdateType(role),
260
- content: text(content),
261
- },
262
- },
263
- ];
280
+ const update: SessionNotification["update"] = {
281
+ sessionUpdate: messageUpdateType(role),
282
+ content: text(content),
283
+ };
284
+ if (parentToolCallId) {
285
+ (update as Record<string, unknown>)._meta = toolMeta(
286
+ "__text__",
287
+ undefined,
288
+ parentToolCallId,
289
+ );
290
+ }
291
+ return [{ sessionId, update }];
264
292
  }
265
293
 
266
294
  const ctx: ChunkHandlerContext = {
@@ -269,6 +297,7 @@ function toAcpNotifications(
269
297
  fileContentCache,
270
298
  client,
271
299
  logger,
300
+ parentToolCallId,
272
301
  };
273
302
  const output: SessionNotification[] = [];
274
303
 
@@ -289,6 +318,7 @@ function streamEventToAcpNotifications(
289
318
  fileContentCache: { [key: string]: string },
290
319
  client: AgentSideConnection,
291
320
  logger: Logger,
321
+ parentToolCallId?: string,
292
322
  ): SessionNotification[] {
293
323
  const event = message.event;
294
324
  switch (event.type) {
@@ -301,6 +331,7 @@ function streamEventToAcpNotifications(
301
331
  fileContentCache,
302
332
  client,
303
333
  logger,
334
+ parentToolCallId,
304
335
  );
305
336
  case "content_block_delta":
306
337
  return toAcpNotifications(
@@ -311,6 +342,7 @@ function streamEventToAcpNotifications(
311
342
  fileContentCache,
312
343
  client,
313
344
  logger,
345
+ parentToolCallId,
314
346
  );
315
347
  case "message_start":
316
348
  case "message_delta":
@@ -439,6 +471,7 @@ export async function handleStreamEvent(
439
471
  context: MessageHandlerContext,
440
472
  ): Promise<void> {
441
473
  const { sessionId, client, toolUseCache, fileContentCache, logger } = context;
474
+ const parentToolCallId = message.parent_tool_use_id ?? undefined;
442
475
 
443
476
  for (const notification of streamEventToAcpNotifications(
444
477
  message,
@@ -447,6 +480,7 @@ export async function handleStreamEvent(
447
480
  fileContentCache,
448
481
  client,
449
482
  logger,
483
+ parentToolCallId,
450
484
  )) {
451
485
  await client.sessionUpdate(notification);
452
486
  context.session.notificationHistory.push(notification);
@@ -543,6 +577,10 @@ export async function handleUserAssistantMessage(
543
577
 
544
578
  const content = message.message.content;
545
579
  const contentToProcess = filterMessageContent(content);
580
+ const parentToolCallId =
581
+ "parent_tool_use_id" in message
582
+ ? (message.parent_tool_use_id ?? undefined)
583
+ : undefined;
546
584
 
547
585
  for (const notification of toAcpNotifications(
548
586
  contentToProcess as typeof content,
@@ -552,6 +590,7 @@ export async function handleUserAssistantMessage(
552
590
  fileContentCache,
553
591
  client,
554
592
  logger,
593
+ parentToolCallId,
555
594
  )) {
556
595
  await client.sessionUpdate(notification);
557
596
  session.notificationHistory.push(notification);
@@ -46,6 +46,7 @@ export type ToolUpdateMeta = {
46
46
  claudeCode?: {
47
47
  toolName: string;
48
48
  toolResponse?: unknown;
49
+ parentToolCallId?: string;
49
50
  };
50
51
  };
51
52
 
@@ -54,6 +54,12 @@ function findCodexBinary(options: CodexProcessOptions): {
54
54
  return { command: options.binaryPath, args: configArgs };
55
55
  }
56
56
 
57
+ if (options.binaryPath) {
58
+ throw new Error(
59
+ `codex-acp binary not found at ${options.binaryPath}. Run "node apps/twig/scripts/download-binaries.mjs" to download it.`,
60
+ );
61
+ }
62
+
57
63
  return { command: "npx", args: ["@zed-industries/codex-acp", ...configArgs] };
58
64
  }
59
65