@posthog/agent 2.1.131 → 2.1.138

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 (40) hide show
  1. package/dist/adapters/claude/conversion/tool-use-to-acp.d.ts +14 -28
  2. package/dist/adapters/claude/conversion/tool-use-to-acp.js +118 -165
  3. package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
  4. package/dist/adapters/claude/permissions/permission-options.js +33 -0
  5. package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
  6. package/dist/adapters/claude/session/jsonl-hydration.d.ts +45 -0
  7. package/dist/adapters/claude/session/jsonl-hydration.js +444 -0
  8. package/dist/adapters/claude/session/jsonl-hydration.js.map +1 -0
  9. package/dist/adapters/claude/tools.js +21 -11
  10. package/dist/adapters/claude/tools.js.map +1 -1
  11. package/dist/agent.d.ts +2 -0
  12. package/dist/agent.js +1261 -608
  13. package/dist/agent.js.map +1 -1
  14. package/dist/posthog-api.js +6 -2
  15. package/dist/posthog-api.js.map +1 -1
  16. package/dist/server/agent-server.js +1307 -657
  17. package/dist/server/agent-server.js.map +1 -1
  18. package/dist/server/bin.cjs +1285 -637
  19. package/dist/server/bin.cjs.map +1 -1
  20. package/package.json +8 -4
  21. package/src/adapters/base-acp-agent.ts +6 -3
  22. package/src/adapters/claude/UPSTREAM.md +63 -0
  23. package/src/adapters/claude/claude-agent.ts +682 -421
  24. package/src/adapters/claude/conversion/sdk-to-acp.ts +249 -85
  25. package/src/adapters/claude/conversion/tool-use-to-acp.ts +176 -150
  26. package/src/adapters/claude/hooks.ts +53 -1
  27. package/src/adapters/claude/permissions/permission-handlers.ts +39 -21
  28. package/src/adapters/claude/session/commands.ts +13 -9
  29. package/src/adapters/claude/session/jsonl-hydration.test.ts +903 -0
  30. package/src/adapters/claude/session/jsonl-hydration.ts +581 -0
  31. package/src/adapters/claude/session/mcp-config.ts +2 -5
  32. package/src/adapters/claude/session/options.ts +58 -6
  33. package/src/adapters/claude/session/settings.ts +326 -0
  34. package/src/adapters/claude/tools.ts +1 -0
  35. package/src/adapters/claude/types.ts +38 -0
  36. package/src/adapters/codex/spawn.ts +1 -1
  37. package/src/agent.ts +4 -0
  38. package/src/execution-mode.ts +26 -10
  39. package/src/server/agent-server.test.ts +41 -1
  40. package/src/utils/common.ts +1 -1
@@ -2,6 +2,7 @@ import type {
2
2
  AgentSideConnection,
3
3
  Role,
4
4
  SessionNotification,
5
+ SessionUpdate,
5
6
  } from "@agentclientprotocol/sdk";
6
7
  import { RequestError } from "@agentclientprotocol/sdk";
7
8
  import type {
@@ -25,6 +26,7 @@ import {
25
26
  type ClaudePlanEntry,
26
27
  planEntries,
27
28
  toolInfoFromToolUse,
29
+ toolUpdateFromEditToolResponse,
28
30
  toolUpdateFromToolResult,
29
31
  } from "./tool-use-to-acp.js";
30
32
 
@@ -51,6 +53,8 @@ type ChunkHandlerContext = {
51
53
  client: AgentSideConnection;
52
54
  logger: Logger;
53
55
  parentToolCallId?: string;
56
+ registerHooks?: boolean;
57
+ supportsTerminalOutput?: boolean;
54
58
  };
55
59
 
56
60
  export interface MessageHandlerContext {
@@ -60,6 +64,8 @@ export interface MessageHandlerContext {
60
64
  toolUseCache: ToolUseCache;
61
65
  fileContentCache: { [key: string]: string };
62
66
  logger: Logger;
67
+ registerHooks?: boolean;
68
+ supportsTerminalOutput?: boolean;
63
69
  }
64
70
 
65
71
  function messageUpdateType(role: Role) {
@@ -81,8 +87,8 @@ function handleTextChunk(
81
87
  chunk: { text: string },
82
88
  role: Role,
83
89
  parentToolCallId?: string,
84
- ): SessionNotification["update"] {
85
- const update: SessionNotification["update"] = {
90
+ ): SessionUpdate {
91
+ const update: SessionUpdate = {
86
92
  sessionUpdate: messageUpdateType(role),
87
93
  content: text(chunk.text),
88
94
  };
@@ -101,7 +107,7 @@ function handleImageChunk(
101
107
  source: { type: string; data?: string; media_type?: string; url?: string };
102
108
  },
103
109
  role: Role,
104
- ): SessionNotification["update"] {
110
+ ): SessionUpdate {
105
111
  return {
106
112
  sessionUpdate: messageUpdateType(role),
107
113
  content: image(
@@ -115,8 +121,8 @@ function handleImageChunk(
115
121
  function handleThinkingChunk(
116
122
  chunk: { thinking: string },
117
123
  parentToolCallId?: string,
118
- ): SessionNotification["update"] {
119
- const update: SessionNotification["update"] = {
124
+ ): SessionUpdate {
125
+ const update: SessionUpdate = {
120
126
  sessionUpdate: "agent_thought_chunk",
121
127
  content: text(chunk.thinking),
122
128
  };
@@ -133,7 +139,8 @@ function handleThinkingChunk(
133
139
  function handleToolUseChunk(
134
140
  chunk: ToolUseCache[string],
135
141
  ctx: ChunkHandlerContext,
136
- ): SessionNotification["update"] | null {
142
+ ): SessionUpdate | null {
143
+ const alreadyCached = chunk.id in ctx.toolUseCache;
137
144
  ctx.toolUseCache[chunk.id] = chunk;
138
145
 
139
146
  if (chunk.name === "TodoWrite") {
@@ -147,25 +154,33 @@ function handleToolUseChunk(
147
154
  return null;
148
155
  }
149
156
 
150
- registerHookCallback(chunk.id, {
151
- onPostToolUseHook: async (toolUseId, _toolInput, toolResponse) => {
152
- const toolUse = ctx.toolUseCache[toolUseId];
153
- if (toolUse) {
154
- await ctx.client.sessionUpdate({
155
- sessionId: ctx.sessionId,
156
- update: {
157
- _meta: toolMeta(toolUse.name, toolResponse, ctx.parentToolCallId),
158
- toolCallId: toolUseId,
159
- sessionUpdate: "tool_call_update",
160
- },
161
- });
162
- } else {
163
- ctx.logger.error(
164
- `Got a tool response for tool use that wasn't tracked: ${toolUseId}`,
165
- );
166
- }
167
- },
168
- });
157
+ if (!alreadyCached && ctx.registerHooks !== false) {
158
+ registerHookCallback(chunk.id, {
159
+ onPostToolUseHook: async (toolUseId, _toolInput, toolResponse) => {
160
+ const toolUse = ctx.toolUseCache[toolUseId];
161
+ if (toolUse) {
162
+ const editUpdate =
163
+ toolUse.name === "Edit"
164
+ ? toolUpdateFromEditToolResponse(toolResponse)
165
+ : null;
166
+
167
+ await ctx.client.sessionUpdate({
168
+ sessionId: ctx.sessionId,
169
+ update: {
170
+ _meta: toolMeta(toolUse.name, toolResponse, ctx.parentToolCallId),
171
+ toolCallId: toolUseId,
172
+ sessionUpdate: "tool_call_update",
173
+ ...(editUpdate ? editUpdate : {}),
174
+ },
175
+ });
176
+ } else {
177
+ ctx.logger.error(
178
+ `Got a tool response for tool use that wasn't tracked: ${toolUseId}`,
179
+ );
180
+ }
181
+ },
182
+ });
183
+ }
169
184
 
170
185
  let rawInput: Record<string, unknown> | undefined;
171
186
  try {
@@ -174,65 +189,133 @@ function handleToolUseChunk(
174
189
  // ignore
175
190
  }
176
191
 
192
+ const toolInfo = toolInfoFromToolUse(chunk, {
193
+ supportsTerminalOutput: ctx.supportsTerminalOutput,
194
+ toolUseId: chunk.id,
195
+ });
196
+
197
+ const meta: Record<string, unknown> = {
198
+ ...toolMeta(chunk.name, undefined, ctx.parentToolCallId),
199
+ };
200
+ if (chunk.name === "Bash" && ctx.supportsTerminalOutput && !alreadyCached) {
201
+ meta.terminal_info = { terminal_id: chunk.id };
202
+ }
203
+
204
+ if (alreadyCached) {
205
+ return {
206
+ _meta: meta,
207
+ toolCallId: chunk.id,
208
+ sessionUpdate: "tool_call_update" as const,
209
+ rawInput,
210
+ ...toolInfo,
211
+ };
212
+ }
213
+
177
214
  return {
178
- _meta: toolMeta(chunk.name, undefined, ctx.parentToolCallId),
215
+ _meta: meta,
179
216
  toolCallId: chunk.id,
180
- sessionUpdate: "tool_call",
217
+ sessionUpdate: "tool_call" as const,
181
218
  rawInput,
182
219
  status: "pending",
183
- ...toolInfoFromToolUse(chunk, ctx.fileContentCache, ctx.logger),
220
+ ...toolInfo,
184
221
  };
185
222
  }
186
223
 
187
224
  function handleToolResultChunk(
188
- chunk: AnthropicContentChunk & { tool_use_id: string; is_error?: boolean },
225
+ chunk: AnthropicContentChunk & {
226
+ tool_use_id: string;
227
+ is_error?: boolean;
228
+ content?: unknown;
229
+ },
189
230
  ctx: ChunkHandlerContext,
190
- ): SessionNotification["update"] | null {
231
+ ): SessionUpdate[] {
191
232
  const toolUse = ctx.toolUseCache[chunk.tool_use_id];
192
233
  if (!toolUse) {
193
234
  ctx.logger.error(
194
235
  `Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`,
195
236
  );
196
- return null;
237
+ return [];
197
238
  }
198
239
 
199
240
  if (toolUse.name === "TodoWrite") {
200
- return null;
241
+ return [];
201
242
  }
202
243
 
203
- return {
204
- _meta: toolMeta(toolUse.name, undefined, ctx.parentToolCallId),
244
+ const { _meta: resultMeta, ...toolUpdate } = toolUpdateFromToolResult(
245
+ chunk as Parameters<typeof toolUpdateFromToolResult>[0],
246
+ toolUse,
247
+ {
248
+ supportsTerminalOutput: ctx.supportsTerminalOutput,
249
+ toolUseId: chunk.tool_use_id,
250
+ },
251
+ );
252
+
253
+ const updates: SessionUpdate[] = [];
254
+
255
+ if (resultMeta?.terminal_output) {
256
+ const terminalOutputMeta: Record<string, unknown> = {
257
+ terminal_output: resultMeta.terminal_output,
258
+ };
259
+ if (ctx.parentToolCallId) {
260
+ terminalOutputMeta.claudeCode = {
261
+ parentToolCallId: ctx.parentToolCallId,
262
+ };
263
+ }
264
+ updates.push({
265
+ _meta: terminalOutputMeta,
266
+ toolCallId: chunk.tool_use_id,
267
+ sessionUpdate: "tool_call_update" as const,
268
+ });
269
+ }
270
+
271
+ const meta: Record<string, unknown> = {
272
+ ...toolMeta(toolUse.name, undefined, ctx.parentToolCallId),
273
+ ...(resultMeta?.terminal_exit
274
+ ? { terminal_exit: resultMeta.terminal_exit }
275
+ : {}),
276
+ };
277
+
278
+ updates.push({
279
+ _meta: meta,
205
280
  toolCallId: chunk.tool_use_id,
206
281
  sessionUpdate: "tool_call_update",
207
282
  status: chunk.is_error ? "failed" : "completed",
208
- ...toolUpdateFromToolResult(
209
- chunk as Parameters<typeof toolUpdateFromToolResult>[0],
210
- toolUse,
211
- ),
212
- };
283
+ rawOutput: chunk.content,
284
+ ...toolUpdate,
285
+ });
286
+
287
+ return updates;
213
288
  }
214
289
 
215
290
  function processContentChunk(
216
291
  chunk: AnthropicContentChunk,
217
292
  role: Role,
218
293
  ctx: ChunkHandlerContext,
219
- ): SessionNotification["update"] | null {
294
+ ): SessionUpdate[] {
220
295
  switch (chunk.type) {
221
296
  case "text":
222
- case "text_delta":
223
- return handleTextChunk(chunk, role, ctx.parentToolCallId);
297
+ case "text_delta": {
298
+ const update = handleTextChunk(chunk, role, ctx.parentToolCallId);
299
+ return update ? [update] : [];
300
+ }
224
301
 
225
- case "image":
226
- return handleImageChunk(chunk, role);
302
+ case "image": {
303
+ const update = handleImageChunk(chunk, role);
304
+ return update ? [update] : [];
305
+ }
227
306
 
228
307
  case "thinking":
229
- case "thinking_delta":
230
- return handleThinkingChunk(chunk, ctx.parentToolCallId);
308
+ case "thinking_delta": {
309
+ const update = handleThinkingChunk(chunk, ctx.parentToolCallId);
310
+ return update ? [update] : [];
311
+ }
231
312
 
232
313
  case "tool_use":
233
314
  case "server_tool_use":
234
- case "mcp_tool_use":
235
- return handleToolUseChunk(chunk as ToolUseCache[string], ctx);
315
+ case "mcp_tool_use": {
316
+ const update = handleToolUseChunk(chunk as ToolUseCache[string], ctx);
317
+ return update ? [update] : [];
318
+ }
236
319
 
237
320
  case "tool_result":
238
321
  case "tool_search_tool_result":
@@ -246,6 +329,7 @@ function processContentChunk(
246
329
  chunk as AnthropicContentChunk & {
247
330
  tool_use_id: string;
248
331
  is_error?: boolean;
332
+ content?: unknown;
249
333
  },
250
334
  ctx,
251
335
  );
@@ -259,11 +343,11 @@ function processContentChunk(
259
343
  case "container_upload":
260
344
  case "compaction":
261
345
  case "compaction_delta":
262
- return null;
346
+ return [];
263
347
 
264
348
  default:
265
- unreachable(chunk, ctx.logger);
266
- return null;
349
+ unreachable(chunk as never, ctx.logger);
350
+ return [];
267
351
  }
268
352
  }
269
353
 
@@ -280,9 +364,11 @@ function toAcpNotifications(
280
364
  client: AgentSideConnection,
281
365
  logger: Logger,
282
366
  parentToolCallId?: string,
367
+ registerHooks?: boolean,
368
+ supportsTerminalOutput?: boolean,
283
369
  ): SessionNotification[] {
284
370
  if (typeof content === "string") {
285
- const update: SessionNotification["update"] = {
371
+ const update: SessionUpdate = {
286
372
  sessionUpdate: messageUpdateType(role),
287
373
  content: text(content),
288
374
  };
@@ -303,12 +389,13 @@ function toAcpNotifications(
303
389
  client,
304
390
  logger,
305
391
  parentToolCallId,
392
+ registerHooks,
393
+ supportsTerminalOutput,
306
394
  };
307
395
  const output: SessionNotification[] = [];
308
396
 
309
397
  for (const chunk of content) {
310
- const update = processContentChunk(chunk, role, ctx);
311
- if (update) {
398
+ for (const update of processContentChunk(chunk, role, ctx)) {
312
399
  output.push({ sessionId, update });
313
400
  }
314
401
  }
@@ -324,6 +411,8 @@ function streamEventToAcpNotifications(
324
411
  client: AgentSideConnection,
325
412
  logger: Logger,
326
413
  parentToolCallId?: string,
414
+ registerHooks?: boolean,
415
+ supportsTerminalOutput?: boolean,
327
416
  ): SessionNotification[] {
328
417
  const event = message.event;
329
418
  switch (event.type) {
@@ -337,6 +426,8 @@ function streamEventToAcpNotifications(
337
426
  client,
338
427
  logger,
339
428
  parentToolCallId,
429
+ registerHooks,
430
+ supportsTerminalOutput,
340
431
  );
341
432
  case "content_block_delta":
342
433
  return toAcpNotifications(
@@ -348,6 +439,8 @@ function streamEventToAcpNotifications(
348
439
  client,
349
440
  logger,
350
441
  parentToolCallId,
442
+ registerHooks,
443
+ supportsTerminalOutput,
351
444
  );
352
445
  case "message_start":
353
446
  case "message_delta":
@@ -356,7 +449,7 @@ function streamEventToAcpNotifications(
356
449
  return [];
357
450
 
358
451
  default:
359
- unreachable(event, logger);
452
+ unreachable(event as never, logger);
360
453
  return [];
361
454
  }
362
455
  }
@@ -413,18 +506,24 @@ export async function handleSystemMessage(
413
506
  }
414
507
  }
415
508
 
509
+ export type ResultMessageHandlerResult = {
510
+ shouldStop: boolean;
511
+ stopReason?: string;
512
+ error?: Error;
513
+ usage?: {
514
+ inputTokens: number;
515
+ outputTokens: number;
516
+ cachedReadTokens: number;
517
+ cachedWriteTokens: number;
518
+ costUsd?: number;
519
+ contextWindowSize?: number;
520
+ };
521
+ };
522
+
416
523
  export function handleResultMessage(
417
524
  message: SDKResultMessage,
418
- context: MessageHandlerContext,
419
- ): { shouldStop: boolean; stopReason?: string; error?: Error } {
420
- const { session } = context;
421
-
422
- if (session.cancelled) {
423
- return {
424
- shouldStop: true,
425
- stopReason: "cancelled",
426
- };
427
- }
525
+ ): ResultMessageHandlerResult {
526
+ const usage = extractUsageFromResult(message);
428
527
 
429
528
  switch (message.subtype) {
430
529
  case "success": {
@@ -432,15 +531,17 @@ export function handleResultMessage(
432
531
  return {
433
532
  shouldStop: true,
434
533
  error: RequestError.authRequired(),
534
+ usage,
435
535
  };
436
536
  }
437
537
  if (message.is_error) {
438
538
  return {
439
539
  shouldStop: true,
440
540
  error: RequestError.internalError(undefined, message.result),
541
+ usage,
441
542
  };
442
543
  }
443
- return { shouldStop: true, stopReason: "end_turn" };
544
+ return { shouldStop: true, stopReason: "end_turn", usage };
444
545
  }
445
546
  case "error_during_execution":
446
547
  if (message.is_error) {
@@ -450,9 +551,10 @@ export function handleResultMessage(
450
551
  undefined,
451
552
  message.errors.join(", ") || message.subtype,
452
553
  ),
554
+ usage,
453
555
  };
454
556
  }
455
- return { shouldStop: true, stopReason: "end_turn" };
557
+ return { shouldStop: true, stopReason: "end_turn", usage };
456
558
  case "error_max_budget_usd":
457
559
  case "error_max_turns":
458
560
  case "error_max_structured_output_retries":
@@ -463,14 +565,46 @@ export function handleResultMessage(
463
565
  undefined,
464
566
  message.errors.join(", ") || message.subtype,
465
567
  ),
568
+ usage,
466
569
  };
467
570
  }
468
- return { shouldStop: true, stopReason: "max_turn_requests" };
571
+ return { shouldStop: true, stopReason: "max_turn_requests", usage };
469
572
  default:
470
- return { shouldStop: false };
573
+ return { shouldStop: false, usage };
471
574
  }
472
575
  }
473
576
 
577
+ function extractUsageFromResult(
578
+ message: SDKResultMessage,
579
+ ): ResultMessageHandlerResult["usage"] {
580
+ const msg = message as Record<string, unknown>;
581
+ const msgUsage = msg.usage as Record<string, number> | undefined;
582
+ if (!msgUsage) return undefined;
583
+
584
+ const modelUsage = msg.modelUsage as
585
+ | Record<string, { contextWindow: number }>
586
+ | undefined;
587
+ let contextWindowSize: number | undefined;
588
+ if (modelUsage) {
589
+ const contextWindows = Object.values(modelUsage).map(
590
+ (m) => m.contextWindow,
591
+ );
592
+ if (contextWindows.length > 0) {
593
+ contextWindowSize = Math.min(...contextWindows);
594
+ }
595
+ }
596
+
597
+ return {
598
+ inputTokens: msgUsage.input_tokens ?? 0,
599
+ outputTokens: msgUsage.output_tokens ?? 0,
600
+ cachedReadTokens: msgUsage.cache_read_input_tokens ?? 0,
601
+ cachedWriteTokens: msgUsage.cache_creation_input_tokens ?? 0,
602
+ costUsd:
603
+ typeof msg.total_cost_usd === "number" ? msg.total_cost_usd : undefined,
604
+ contextWindowSize,
605
+ };
606
+ }
607
+
474
608
  export async function handleStreamEvent(
475
609
  message: SDKPartialAssistantMessage,
476
610
  context: MessageHandlerContext,
@@ -486,6 +620,8 @@ export async function handleStreamEvent(
486
620
  client,
487
621
  logger,
488
622
  parentToolCallId,
623
+ context.registerHooks,
624
+ context.supportsTerminalOutput,
489
625
  )) {
490
626
  await client.sessionUpdate(notification);
491
627
  context.session.notificationHistory.push(notification);
@@ -504,16 +640,6 @@ function hasLocalCommandStderr(content: AnthropicMessageContent): boolean {
504
640
  );
505
641
  }
506
642
 
507
- function isSimpleUserMessage(message: AnthropicMessageWithContent): boolean {
508
- return (
509
- message.type === "user" &&
510
- (typeof message.message.content === "string" ||
511
- (Array.isArray(message.message.content) &&
512
- message.message.content.length === 1 &&
513
- message.message.content[0].type === "text"))
514
- );
515
- }
516
-
517
643
  function isLoginRequiredMessage(message: AnthropicMessageWithContent): boolean {
518
644
  return (
519
645
  message.type === "assistant" &&
@@ -525,13 +651,23 @@ function isLoginRequiredMessage(message: AnthropicMessageWithContent): boolean {
525
651
  );
526
652
  }
527
653
 
654
+ function isPlainTextUserMessage(message: AnthropicMessageWithContent): boolean {
655
+ const content = message.message.content;
656
+ return (
657
+ message.type === "user" &&
658
+ (typeof content === "string" ||
659
+ (Array.isArray(content) &&
660
+ content.length === 1 &&
661
+ content[0].type === "text"))
662
+ );
663
+ }
664
+
528
665
  function shouldSkipUserAssistantMessage(
529
666
  message: AnthropicMessageWithContent,
530
667
  ): boolean {
531
668
  return (
532
669
  hasLocalCommandStdout(message.message.content) ||
533
670
  hasLocalCommandStderr(message.message.content) ||
534
- isSimpleUserMessage(message) ||
535
671
  isLoginRequiredMessage(message)
536
672
  );
537
673
  }
@@ -567,11 +703,31 @@ export async function handleUserAssistantMessage(
567
703
  const { session, sessionId, client, toolUseCache, fileContentCache, logger } =
568
704
  context;
569
705
 
570
- if (session.cancelled) {
571
- return {};
572
- }
573
-
574
706
  if (shouldSkipUserAssistantMessage(message)) {
707
+ const content = message.message.content;
708
+
709
+ // Handle /context by sending its reply as a regular agent message
710
+ if (
711
+ typeof content === "string" &&
712
+ hasLocalCommandStdout(content) &&
713
+ content.includes("Context Usage")
714
+ ) {
715
+ const stripped = content
716
+ .replace("<local-command-stdout>", "")
717
+ .replace("</local-command-stdout>", "");
718
+ for (const notification of toAcpNotifications(
719
+ stripped,
720
+ "assistant",
721
+ sessionId,
722
+ toolUseCache,
723
+ fileContentCache,
724
+ client,
725
+ logger,
726
+ )) {
727
+ await client.sessionUpdate(notification);
728
+ }
729
+ }
730
+
575
731
  logSpecialMessages(message, logger);
576
732
 
577
733
  if (isLoginRequiredMessage(message)) {
@@ -580,8 +736,14 @@ export async function handleUserAssistantMessage(
580
736
  return {};
581
737
  }
582
738
 
739
+ // Skip plain text user messages (already displayed by the ACP client)
740
+ if (isPlainTextUserMessage(message)) {
741
+ return {};
742
+ }
743
+
583
744
  const content = message.message.content;
584
- const contentToProcess = filterMessageContent(content);
745
+ const contentToProcess =
746
+ message.type === "assistant" ? filterMessageContent(content) : content;
585
747
  const parentToolCallId =
586
748
  "parent_tool_use_id" in message
587
749
  ? (message.parent_tool_use_id ?? undefined)
@@ -596,6 +758,8 @@ export async function handleUserAssistantMessage(
596
758
  client,
597
759
  logger,
598
760
  parentToolCallId,
761
+ context.registerHooks,
762
+ context.supportsTerminalOutput,
599
763
  )) {
600
764
  await client.sessionUpdate(notification);
601
765
  session.notificationHistory.push(notification);