claude-code-rust 0.14.3 → 0.14.5

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.
@@ -1,16 +1,16 @@
1
1
  import { asRecordOrNull } from "./shared.js";
2
- import { toPermissionMode, buildModeState, refreshSupportedModesForSession } from "./commands.js";
2
+ import { toPermissionMode, buildModeState, refreshSupportedModesForSession, } from "./commands.js";
3
3
  import { writeEvent, emitSessionUpdate, emitConnectEvent, emitSessionReplacedEvent, } from "./events.js";
4
4
  import { TOOL_RESULT_TYPES, isToolSearchToolName, isToolSearchToolResultType, unwrapToolUseResult, parseToolNonExecutionMetadata, } from "./tooling.js";
5
5
  import { emitToolCall, emitToolCallUpdate, emitToolResultUpdate, finalizeOpenToolCalls, emitToolProgressUpdate, emitToolSummaryUpdate, ensureToolCallVisible, resolveTaskToolUseId, defersTaskNotificationCompletion, toolAcceptsTaskLifecycle, taskProgressText, taskUpdatedFields, } from "./tool_calls.js";
6
- import { applyBackgroundTasksChanged, applyTaskLifecycleState } from "./tasks.js";
6
+ import { applyBackgroundTasksChanged, applyTaskLifecycleState, } from "./tasks.js";
7
7
  import { linkTaskToolUse, unlinkTaskToolUse } from "./task_links.js";
8
8
  import { emitAuthRequired, classifyTurnErrorKind, emitFastModeUpdate, emitFastModeUpdateIfChanged, setFastModeSnapshotIfChanged, } from "./error_classification.js";
9
- import { mapAvailableAgentsFromNames, emitAvailableAgentsIfChanged, refreshAvailableAgents } from "./agents.js";
9
+ import { mapAvailableAgentsFromNames, emitAvailableAgentsIfChanged, refreshAvailableAgents, } from "./agents.js";
10
10
  import { mapInitSlashCommands, mapSdkSlashCommands, updateAvailableCommands, } from "./available_commands.js";
11
11
  import { buildApiRetryUpdate, buildRateLimitUpdate, buildSubagentRetryUpdate, normalizeSettingsParseErrors, nonNegativeIntegerField, numberField, parseApiRetryError, parseRuntimeSessionState, } from "./state_parsing.js";
12
12
  import { looksLikeAuthRequired } from "./auth.js";
13
- import { emitCurrentModelUpdate, refreshCurrentModel, updateSessionId } from "./session_lifecycle.js";
13
+ import { emitCurrentModelUpdate, refreshCurrentModel, updateSessionId, } from "./session_lifecycle.js";
14
14
  import { bridgeLogger, LOG_TARGETS } from "./logger.js";
15
15
  import { emitMcpSnapshotFromStatuses } from "./mcp.js";
16
16
  export function textFromPrompt(command) {
@@ -38,23 +38,46 @@ function sdkCorrelationMetadata(msg) {
38
38
  return {
39
39
  requestId: typeof msg.request_id === "string" ? msg.request_id : undefined,
40
40
  subagentType: typeof msg.subagent_type === "string" ? msg.subagent_type : undefined,
41
- taskDescription: typeof msg.task_description === "string" ? msg.task_description : undefined,
41
+ taskDescription: typeof msg.task_description === "string"
42
+ ? msg.task_description
43
+ : undefined,
42
44
  parentAgentId: typeof msg.parent_agent_id === "string" ? msg.parent_agent_id : undefined,
43
45
  };
44
46
  }
45
47
  function sdkTaskMetadata(msg) {
46
48
  const metadata = sdkCorrelationMetadata(msg);
47
- const taskType = typeof msg.task_type === "string" && msg.task_type.length > 0 ? msg.task_type : undefined;
48
- const workflowName = typeof msg.workflow_name === "string" && msg.workflow_name.length > 0 ? msg.workflow_name : undefined;
49
- const prompt = typeof msg.prompt === "string" && msg.prompt.length > 0 ? msg.prompt : undefined;
50
- const outputFile = typeof msg.output_file === "string" && msg.output_file.length > 0 ? msg.output_file : undefined;
51
- const status = typeof msg.status === "string" && msg.status.length > 0 ? msg.status : undefined;
52
- const summary = status && typeof msg.summary === "string" && msg.summary.length > 0 ? msg.summary : undefined;
49
+ const taskType = typeof msg.task_type === "string" && msg.task_type.length > 0
50
+ ? msg.task_type
51
+ : undefined;
52
+ const workflowName = typeof msg.workflow_name === "string" && msg.workflow_name.length > 0
53
+ ? msg.workflow_name
54
+ : undefined;
55
+ const prompt = typeof msg.prompt === "string" && msg.prompt.length > 0
56
+ ? msg.prompt
57
+ : undefined;
58
+ const outputFile = typeof msg.output_file === "string" && msg.output_file.length > 0
59
+ ? msg.output_file
60
+ : undefined;
61
+ const status = typeof msg.status === "string" && msg.status.length > 0
62
+ ? msg.status
63
+ : undefined;
64
+ const summary = status && typeof msg.summary === "string" && msg.summary.length > 0
65
+ ? msg.summary
66
+ : undefined;
67
+ const spawnDepth = typeof msg.spawn_depth === "number" &&
68
+ Number.isSafeInteger(msg.spawn_depth) &&
69
+ msg.spawn_depth > 0
70
+ ? msg.spawn_depth
71
+ : undefined;
53
72
  const taskMetadata = {
54
73
  ...(metadata.requestId ? { request_id: metadata.requestId } : {}),
55
74
  ...(metadata.subagentType ? { subagent_type: metadata.subagentType } : {}),
56
- ...(metadata.taskDescription ? { task_description: metadata.taskDescription } : {}),
57
- ...(metadata.parentAgentId ? { parent_agent_id: metadata.parentAgentId } : {}),
75
+ ...(metadata.taskDescription
76
+ ? { task_description: metadata.taskDescription }
77
+ : {}),
78
+ ...(metadata.parentAgentId
79
+ ? { parent_agent_id: metadata.parentAgentId }
80
+ : {}),
58
81
  ...(taskType ? { task_type: taskType } : {}),
59
82
  ...(workflowName ? { workflow_name: workflowName } : {}),
60
83
  ...(prompt ? { prompt } : {}),
@@ -62,14 +85,78 @@ function sdkTaskMetadata(msg) {
62
85
  ...(summary ? { summary } : {}),
63
86
  ...(status ? { terminal_status: status } : {}),
64
87
  ...(typeof msg.blocked === "boolean" ? { blocked: msg.blocked } : {}),
88
+ ...(typeof msg.is_backgrounded === "boolean"
89
+ ? { is_backgrounded: msg.is_backgrounded }
90
+ : {}),
91
+ ...(spawnDepth !== undefined ? { spawn_depth: spawnDepth } : {}),
65
92
  };
66
93
  return Object.keys(taskMetadata).length > 0 ? taskMetadata : undefined;
67
94
  }
68
95
  function sdkMessageOriginKind(msg) {
69
- const origin = msg.origin && typeof msg.origin === "object" ? msg.origin : null;
96
+ const origin = msg.origin && typeof msg.origin === "object"
97
+ ? msg.origin
98
+ : null;
70
99
  return typeof origin?.kind === "string" ? origin.kind : undefined;
71
100
  }
101
+ function externalMessageUpdateFromSdkUser(msg) {
102
+ const origin = asRecordOrNull(msg.origin);
103
+ if (!origin) {
104
+ return undefined;
105
+ }
106
+ const kind = typeof origin?.kind === "string" ? origin.kind : undefined;
107
+ if (kind !== "peer" && kind !== "task-notification") {
108
+ return undefined;
109
+ }
110
+ const payload = asRecordOrNull(msg.message);
111
+ const content = payload?.content;
112
+ const contentText = typeof content === "string"
113
+ ? content
114
+ : Array.isArray(content)
115
+ ? content
116
+ .flatMap((block) => {
117
+ const record = asRecordOrNull(block);
118
+ return record?.type === "text" && typeof record.text === "string"
119
+ ? [record.text]
120
+ : [];
121
+ })
122
+ .join("\n")
123
+ : "";
124
+ const text = typeof origin.body === "string" ? origin.body : contentText;
125
+ if (!text.trim()) {
126
+ return undefined;
127
+ }
128
+ return {
129
+ type: "external_message_update",
130
+ content: text,
131
+ ...(sourceMessageUuid(msg)
132
+ ? { source_message_uuid: sourceMessageUuid(msg) }
133
+ : {}),
134
+ origin: {
135
+ kind,
136
+ ...(typeof origin.subkind === "string"
137
+ ? { subkind: origin.subkind }
138
+ : {}),
139
+ ...(typeof origin.from === "string" ? { from: origin.from } : {}),
140
+ ...(typeof origin.name === "string" ? { name: origin.name } : {}),
141
+ ...(typeof origin.fromSession === "string"
142
+ ? { from_session: origin.fromSession }
143
+ : {}),
144
+ ...(typeof origin.senderTaskId === "string"
145
+ ? { sender_task_id: origin.senderTaskId }
146
+ : {}),
147
+ ...(typeof origin.verifiedPeerPid === "number" &&
148
+ Number.isSafeInteger(origin.verifiedPeerPid) &&
149
+ origin.verifiedPeerPid >= 0
150
+ ? { verified_peer_pid: origin.verifiedPeerPid }
151
+ : {}),
152
+ ...(origin.fromMode === "bypass" || origin.fromMode === "prompting"
153
+ ? { from_mode: origin.fromMode }
154
+ : {}),
155
+ },
156
+ };
157
+ }
72
158
  function logSdkMessageOrigin(session, msg) {
159
+ const origin = asRecordOrNull(msg.origin);
73
160
  const originKind = sdkMessageOriginKind(msg);
74
161
  if (!originKind) {
75
162
  return;
@@ -83,6 +170,19 @@ function logSdkMessageOrigin(session, msg) {
83
170
  fields: {
84
171
  message_type: typeof msg.type === "string" ? msg.type : undefined,
85
172
  origin_kind: originKind,
173
+ origin_subkind: typeof origin?.subkind === "string" ? origin.subkind : undefined,
174
+ origin_from_session: typeof origin?.fromSession === "string"
175
+ ? origin.fromSession
176
+ : undefined,
177
+ origin_sender_task_id: typeof origin?.senderTaskId === "string"
178
+ ? origin.senderTaskId
179
+ : undefined,
180
+ origin_verified_peer_pid: typeof origin?.verifiedPeerPid === "number"
181
+ ? origin.verifiedPeerPid
182
+ : undefined,
183
+ origin_from_mode: origin?.fromMode === "bypass" || origin?.fromMode === "prompting"
184
+ ? origin.fromMode
185
+ : undefined,
86
186
  },
87
187
  });
88
188
  }
@@ -91,7 +191,11 @@ function emitSystemNoticeUpdate(session, severity, message) {
91
191
  if (!trimmed) {
92
192
  return;
93
193
  }
94
- emitSessionUpdate(session.sessionId, { type: "system_notice_update", severity, message: trimmed });
194
+ emitSessionUpdate(session.sessionId, {
195
+ type: "system_notice_update",
196
+ severity,
197
+ message: trimmed,
198
+ });
95
199
  }
96
200
  const MAX_INFORMATIONAL_DEDUP_KEYS = 256;
97
201
  function shouldEmitInformationalMessage(session, level, content, toolUseId) {
@@ -203,7 +307,9 @@ function handleModelRefusalNoFallbackMessage(session, msg) {
203
307
  }
204
308
  function workerShutdownMessage(reason) {
205
309
  const trimmed = reason.trim();
206
- return trimmed ? `Claude worker is shutting down: ${trimmed}` : "Claude worker is shutting down.";
310
+ return trimmed
311
+ ? `Claude worker is shutting down: ${trimmed}`
312
+ : "Claude worker is shutting down.";
207
313
  }
208
314
  function handleWorkerShuttingDownSystemMessage(session, msg) {
209
315
  const reason = typeof msg.reason === "string" ? msg.reason.trim() : "";
@@ -280,7 +386,9 @@ export function contentFromPrompt(command) {
280
386
  }
281
387
  }
282
388
  else if (chunk.kind === "image") {
283
- const val = chunk.value && typeof chunk.value === "object" ? chunk.value : null;
389
+ const val = chunk.value && typeof chunk.value === "object"
390
+ ? chunk.value
391
+ : null;
284
392
  if (!val)
285
393
  continue;
286
394
  const data = typeof val.data === "string" ? val.data : "";
@@ -400,7 +508,9 @@ export function handleTaskSystemMessage(session, subtype, msg) {
400
508
  const fields = {
401
509
  status: "in_progress",
402
510
  raw_output: description,
403
- content: [{ type: "content", content: { type: "text", text: description } }],
511
+ content: [
512
+ { type: "content", content: { type: "text", text: description } },
513
+ ],
404
514
  ...(messageTaskMetadata ? { task_metadata: messageTaskMetadata } : {}),
405
515
  };
406
516
  emitToolCallUpdate(session, toolUseId, fields, "task_started");
@@ -423,7 +533,10 @@ export function handleTaskSystemMessage(session, subtype, msg) {
423
533
  if (subtype === "task_updated") {
424
534
  const fields = taskUpdatedFields(msg);
425
535
  if (messageTaskMetadata) {
426
- fields.task_metadata = { ...(fields.task_metadata ?? {}), ...messageTaskMetadata };
536
+ fields.task_metadata = {
537
+ ...(fields.task_metadata ?? {}),
538
+ ...messageTaskMetadata,
539
+ };
427
540
  }
428
541
  if (Object.keys(fields).length === 0) {
429
542
  return true;
@@ -451,15 +564,23 @@ export function handleTaskSystemMessage(session, subtype, msg) {
451
564
  }
452
565
  const status = typeof msg.status === "string" ? msg.status : "";
453
566
  const summary = typeof msg.summary === "string" ? msg.summary : "";
454
- const finalStatus = status === "completed" ? "completed" : status === "stopped" ? "killed" : "failed";
567
+ const finalStatus = status === "completed"
568
+ ? "completed"
569
+ : status === "stopped"
570
+ ? "killed"
571
+ : "failed";
455
572
  const deferCompletion = finalStatus === "completed" && defersTaskNotificationCompletion(toolCall);
456
- const fields = deferCompletion ? {} : { status: finalStatus };
573
+ const fields = deferCompletion
574
+ ? {}
575
+ : { status: finalStatus };
457
576
  if (messageTaskMetadata) {
458
577
  fields.task_metadata = messageTaskMetadata;
459
578
  }
460
579
  if (summary) {
461
580
  fields.raw_output = summary;
462
- fields.content = [{ type: "content", content: { type: "text", text: summary } }];
581
+ fields.content = [
582
+ { type: "content", content: { type: "text", text: summary } },
583
+ ];
463
584
  }
464
585
  if (Object.keys(fields).length > 0) {
465
586
  emitToolCallUpdate(session, toolUseId, fields, "task_notification");
@@ -510,10 +631,19 @@ function emitTranscriptRetraction(session, messageUuids, reason, metadata = {})
510
631
  ...(metadata.requestId ? { request_id: metadata.requestId } : {}),
511
632
  ...(metadata.trigger ? { trigger: metadata.trigger } : {}),
512
633
  ...(metadata.direction ? { direction: metadata.direction } : {}),
513
- ...(metadata.originalModel ? { original_model: metadata.originalModel } : {}),
514
- ...(metadata.fallbackModel ? { fallback_model: metadata.fallbackModel } : {}),
515
- ...(metadata.apiRefusalCategory ? { api_refusal_category: metadata.apiRefusalCategory } : {}),
516
- ...(metadata.apiRefusalExplanation ? { api_refusal_explanation: metadata.apiRefusalExplanation } : {}),
634
+ ...(metadata.originalModel
635
+ ? { original_model: metadata.originalModel }
636
+ : {}),
637
+ ...(metadata.fallbackModel
638
+ ? { fallback_model: metadata.fallbackModel }
639
+ : {}),
640
+ ...(metadata.scope ? { scope: metadata.scope } : {}),
641
+ ...(metadata.apiRefusalCategory
642
+ ? { api_refusal_category: metadata.apiRefusalCategory }
643
+ : {}),
644
+ ...(metadata.apiRefusalExplanation
645
+ ? { api_refusal_explanation: metadata.apiRefusalExplanation }
646
+ : {}),
517
647
  ...(metadata.content ? { content: metadata.content } : {}),
518
648
  });
519
649
  return true;
@@ -530,6 +660,7 @@ function handleFallbackRetractionMessage(session, subtype, msg) {
530
660
  direction: stringField(msg, "direction"),
531
661
  originalModel: stringField(msg, "original_model"),
532
662
  fallbackModel: stringField(msg, "fallback_model"),
663
+ scope: stringField(msg, "scope") ?? "session",
533
664
  apiRefusalCategory: nullableStringField(msg, "api_refusal_category"),
534
665
  apiRefusalExplanation: nullableStringField(msg, "api_refusal_explanation"),
535
666
  content: stringField(msg, "content"),
@@ -549,6 +680,7 @@ function handleFallbackRetractionMessage(session, subtype, msg) {
549
680
  direction: metadata.direction,
550
681
  original_model: metadata.originalModel,
551
682
  fallback_model: metadata.fallbackModel,
683
+ scope: metadata.scope,
552
684
  api_refusal_category: metadata.apiRefusalCategory,
553
685
  has_api_refusal_explanation: metadata.apiRefusalExplanation !== undefined,
554
686
  has_content: metadata.content !== undefined,
@@ -621,7 +753,9 @@ export function handleContentBlock(session, block, linkage) {
621
753
  emitSessionUpdate(session.sessionId, {
622
754
  type: "agent_message_chunk",
623
755
  content: { type: "text", text },
624
- ...(linkage?.sourceMessageUuid ? { source_message_uuid: linkage.sourceMessageUuid } : {}),
756
+ ...(linkage?.sourceMessageUuid
757
+ ? { source_message_uuid: linkage.sourceMessageUuid }
758
+ : {}),
625
759
  });
626
760
  }
627
761
  return;
@@ -632,15 +766,21 @@ export function handleContentBlock(session, block, linkage) {
632
766
  emitSessionUpdate(session.sessionId, {
633
767
  type: "agent_thought_chunk",
634
768
  content: { type: "text", text },
635
- ...(linkage?.sourceMessageUuid ? { source_message_uuid: linkage.sourceMessageUuid } : {}),
769
+ ...(linkage?.sourceMessageUuid
770
+ ? { source_message_uuid: linkage.sourceMessageUuid }
771
+ : {}),
636
772
  });
637
773
  }
638
774
  return;
639
775
  }
640
- if (blockType === "tool_use" || blockType === "server_tool_use" || blockType === "mcp_tool_use") {
776
+ if (blockType === "tool_use" ||
777
+ blockType === "server_tool_use" ||
778
+ blockType === "mcp_tool_use") {
641
779
  const toolUseId = typeof block.id === "string" ? block.id : "";
642
780
  const name = typeof block.name === "string" ? block.name : "Tool";
643
- const input = block.input && typeof block.input === "object" ? block.input : {};
781
+ const input = block.input && typeof block.input === "object"
782
+ ? block.input
783
+ : {};
644
784
  if (!toolUseId) {
645
785
  return;
646
786
  }
@@ -688,7 +828,9 @@ export function handleStreamEvent(session, event, parentToolUseId, sourceMessage
688
828
  emitSessionUpdate(session.sessionId, {
689
829
  type: "agent_message_chunk",
690
830
  content: { type: "text", text },
691
- ...(sourceMessageUuid ? { source_message_uuid: sourceMessageUuid } : {}),
831
+ ...(sourceMessageUuid
832
+ ? { source_message_uuid: sourceMessageUuid }
833
+ : {}),
692
834
  });
693
835
  }
694
836
  }
@@ -698,7 +840,9 @@ export function handleStreamEvent(session, event, parentToolUseId, sourceMessage
698
840
  emitSessionUpdate(session.sessionId, {
699
841
  type: "agent_thought_chunk",
700
842
  content: { type: "text", text },
701
- ...(sourceMessageUuid ? { source_message_uuid: sourceMessageUuid } : {}),
843
+ ...(sourceMessageUuid
844
+ ? { source_message_uuid: sourceMessageUuid }
845
+ : {}),
702
846
  });
703
847
  }
704
848
  }
@@ -718,7 +862,30 @@ export function handleAssistantMessage(session, message) {
718
862
  if (!messageObject) {
719
863
  return;
720
864
  }
721
- const content = Array.isArray(messageObject.content) ? messageObject.content : [];
865
+ const content = Array.isArray(messageObject.content)
866
+ ? messageObject.content
867
+ : [];
868
+ if (asRecordOrNull(message.context_usage)) {
869
+ const markdown = content
870
+ .flatMap((block) => {
871
+ const record = asRecordOrNull(block);
872
+ return record?.type === "text" &&
873
+ typeof record.text === "string" &&
874
+ record.text.trim().length > 0
875
+ ? [record.text]
876
+ : [];
877
+ })
878
+ .join("\n\n");
879
+ if (markdown.length > 0) {
880
+ emitSessionUpdate(session.sessionId, {
881
+ type: "agent_message_chunk",
882
+ content: { type: "text", text: markdown },
883
+ ...(assistantMessageUuid
884
+ ? { source_message_uuid: assistantMessageUuid }
885
+ : {}),
886
+ });
887
+ }
888
+ }
722
889
  for (const block of content) {
723
890
  if (!block || typeof block !== "object") {
724
891
  continue;
@@ -729,7 +896,9 @@ export function handleAssistantMessage(session, message) {
729
896
  blockType === "server_tool_use" ||
730
897
  blockType === "mcp_tool_use" ||
731
898
  TOOL_RESULT_TYPES.has(blockType)) {
732
- const parentToolUseId = typeof message.parent_tool_use_id === "string" ? message.parent_tool_use_id : undefined;
899
+ const parentToolUseId = typeof message.parent_tool_use_id === "string"
900
+ ? message.parent_tool_use_id
901
+ : undefined;
733
902
  handleContentBlock(session, blockRecord, {
734
903
  source: "assistant",
735
904
  parentToolUseId,
@@ -755,7 +924,9 @@ export function handleUserToolResultBlocks(session, message) {
755
924
  if (!messageObject) {
756
925
  return false;
757
926
  }
758
- const content = Array.isArray(messageObject.content) ? messageObject.content : [];
927
+ const content = Array.isArray(messageObject.content)
928
+ ? messageObject.content
929
+ : [];
759
930
  const nonExecutionByToolUseId = parseToolNonExecutionMetadata(message.tool_result_meta);
760
931
  let handled = false;
761
932
  for (const block of content) {
@@ -765,8 +936,12 @@ export function handleUserToolResultBlocks(session, message) {
765
936
  const blockRecord = block;
766
937
  const blockType = typeof blockRecord.type === "string" ? blockRecord.type : "";
767
938
  if (TOOL_RESULT_TYPES.has(blockType)) {
768
- const parentToolUseId = typeof message.parent_tool_use_id === "string" ? message.parent_tool_use_id : undefined;
769
- const toolUseId = typeof blockRecord.tool_use_id === "string" ? blockRecord.tool_use_id : "";
939
+ const parentToolUseId = typeof message.parent_tool_use_id === "string"
940
+ ? message.parent_tool_use_id
941
+ : undefined;
942
+ const toolUseId = typeof blockRecord.tool_use_id === "string"
943
+ ? blockRecord.tool_use_id
944
+ : "";
770
945
  if (!toolUseId) {
771
946
  continue;
772
947
  }
@@ -798,9 +973,30 @@ export function handleResultMessage(session, message) {
798
973
  });
799
974
  return;
800
975
  }
801
- const errors = Array.isArray(message.errors) && message.errors.every((entry) => typeof entry === "string")
976
+ const errors = Array.isArray(message.errors) &&
977
+ message.errors.every((entry) => typeof entry === "string")
802
978
  ? message.errors
803
979
  : [];
980
+ const resumeDropsTurnRefusal = errors.find((entry) => entry.startsWith("Resume rejected by --resume-drops-turn:"));
981
+ if (session.deferConnect &&
982
+ session.resumeDropsTurn &&
983
+ resumeDropsTurnRefusal) {
984
+ session.initializationReady = false;
985
+ session.initializationError = resumeDropsTurnRefusal;
986
+ bridgeLogger.warn({
987
+ target: LOG_TARGETS.APP_SESSION,
988
+ eventName: "session_resume_drops_turn_rejected",
989
+ message: "guarded resume candidate rejected because the source session changed",
990
+ outcome: "failure",
991
+ sessionId: session.sessionId,
992
+ fields: {
993
+ drop_turn_id: session.resumeDropsTurn,
994
+ validation_fence_complete: session.resumeGuardFenceComplete === true,
995
+ error_message: resumeDropsTurnRefusal,
996
+ },
997
+ });
998
+ return;
999
+ }
804
1000
  const assistantError = session.lastAssistantError;
805
1001
  const authHint = errors.find((entry) => looksLikeAuthRequired(entry));
806
1002
  if (authHint) {
@@ -820,7 +1016,9 @@ export function handleResultMessage(session, message) {
820
1016
  error_kind: errorKind,
821
1017
  ...(subtype ? { sdk_result_subtype: subtype } : {}),
822
1018
  ...(assistantError ? { assistant_error: assistantError } : {}),
823
- ...(apiErrorStatus !== undefined ? { api_error_status: apiErrorStatus } : {}),
1019
+ ...(apiErrorStatus !== undefined
1020
+ ? { api_error_status: apiErrorStatus }
1021
+ : {}),
824
1022
  ...(terminalReason ? { terminal_reason: terminalReason } : {}),
825
1023
  });
826
1024
  session.lastAssistantError = undefined;
@@ -940,8 +1138,12 @@ export function handleSdkMessage(session, message) {
940
1138
  fields: {
941
1139
  tool_name: typeof msg.tool_name === "string" ? msg.tool_name : undefined,
942
1140
  agent_id: typeof msg.agent_id === "string" ? msg.agent_id : undefined,
943
- decision_reason_type: typeof msg.decision_reason_type === "string" ? msg.decision_reason_type : undefined,
944
- decision_reason: typeof msg.decision_reason === "string" ? msg.decision_reason : undefined,
1141
+ decision_reason_type: typeof msg.decision_reason_type === "string"
1142
+ ? msg.decision_reason_type
1143
+ : undefined,
1144
+ decision_reason: typeof msg.decision_reason === "string"
1145
+ ? msg.decision_reason
1146
+ : undefined,
945
1147
  denial_message: typeof msg.message === "string" ? msg.message : undefined,
946
1148
  },
947
1149
  });
@@ -956,9 +1158,15 @@ export function handleSdkMessage(session, message) {
956
1158
  sessionId: session.sessionId,
957
1159
  fields: {
958
1160
  sdk_subtype: subtype,
959
- memory_count: Array.isArray(msg.memories) ? msg.memories.length : undefined,
960
- estimated_tokens: typeof msg.estimated_tokens === "number" ? msg.estimated_tokens : undefined,
961
- estimated_tokens_delta: typeof msg.estimated_tokens_delta === "number" ? msg.estimated_tokens_delta : undefined,
1161
+ memory_count: Array.isArray(msg.memories)
1162
+ ? msg.memories.length
1163
+ : undefined,
1164
+ estimated_tokens: typeof msg.estimated_tokens === "number"
1165
+ ? msg.estimated_tokens
1166
+ : undefined,
1167
+ estimated_tokens_delta: typeof msg.estimated_tokens_delta === "number"
1168
+ ? msg.estimated_tokens_delta
1169
+ : undefined,
962
1170
  },
963
1171
  });
964
1172
  return;
@@ -987,7 +1195,9 @@ export function handleSdkMessage(session, message) {
987
1195
  const modelName = typeof msg.model === "string" ? msg.model : session.model;
988
1196
  session.model = modelName;
989
1197
  const currentModelChanged = refreshCurrentModel(session, false);
990
- const incomingMode = typeof msg.permissionMode === "string" ? toPermissionMode(msg.permissionMode) : null;
1198
+ const incomingMode = typeof msg.permissionMode === "string"
1199
+ ? toPermissionMode(msg.permissionMode)
1200
+ : null;
991
1201
  if (incomingMode) {
992
1202
  session.mode = incomingMode;
993
1203
  }
@@ -1019,7 +1229,8 @@ export function handleSdkMessage(session, message) {
1019
1229
  if (Array.isArray(msg.mcp_servers)) {
1020
1230
  emitMcpSnapshotFromStatuses(session, msg.mcp_servers, "init");
1021
1231
  }
1022
- if (session.lastAvailableAgentsSignature === undefined && Array.isArray(msg.agents)) {
1232
+ if (session.lastAvailableAgentsSignature === undefined &&
1233
+ Array.isArray(msg.agents)) {
1023
1234
  emitAvailableAgentsIfChanged(session, mapAvailableAgentsFromNames(msg.agents));
1024
1235
  }
1025
1236
  void session.query
@@ -1041,17 +1252,28 @@ export function handleSdkMessage(session, message) {
1041
1252
  return;
1042
1253
  }
1043
1254
  if (subtype === "status") {
1044
- const mode = typeof msg.permissionMode === "string" ? toPermissionMode(msg.permissionMode) : null;
1255
+ const mode = typeof msg.permissionMode === "string"
1256
+ ? toPermissionMode(msg.permissionMode)
1257
+ : null;
1045
1258
  if (mode) {
1046
1259
  session.mode = mode;
1047
1260
  refreshSupportedModesForSession(session);
1048
- emitSessionUpdate(session.sessionId, { type: "current_mode_update", current_mode_id: mode });
1261
+ emitSessionUpdate(session.sessionId, {
1262
+ type: "current_mode_update",
1263
+ current_mode_id: mode,
1264
+ });
1049
1265
  }
1050
1266
  if (msg.status === "compacting") {
1051
- emitSessionUpdate(session.sessionId, { type: "compaction_update", phase: "started" });
1267
+ emitSessionUpdate(session.sessionId, {
1268
+ type: "compaction_update",
1269
+ phase: "started",
1270
+ });
1052
1271
  }
1053
1272
  else if (msg.status === "requesting") {
1054
- emitSessionUpdate(session.sessionId, { type: "session_status_update", status: "requesting" });
1273
+ emitSessionUpdate(session.sessionId, {
1274
+ type: "session_status_update",
1275
+ status: "requesting",
1276
+ });
1055
1277
  }
1056
1278
  else if (msg.status === null) {
1057
1279
  if (msg.compact_result === "success") {
@@ -1062,7 +1284,8 @@ export function handleSdkMessage(session, message) {
1062
1284
  });
1063
1285
  }
1064
1286
  else if (msg.compact_result === "failed") {
1065
- const compactError = typeof msg.compact_error === "string" && msg.compact_error.trim().length > 0
1287
+ const compactError = typeof msg.compact_error === "string" &&
1288
+ msg.compact_error.trim().length > 0
1066
1289
  ? msg.compact_error.trim()
1067
1290
  : undefined;
1068
1291
  emitSessionUpdate(session.sessionId, {
@@ -1073,7 +1296,10 @@ export function handleSdkMessage(session, message) {
1073
1296
  ...(compactError ? { error: compactError } : {}),
1074
1297
  });
1075
1298
  }
1076
- emitSessionUpdate(session.sessionId, { type: "session_status_update", status: "idle" });
1299
+ emitSessionUpdate(session.sessionId, {
1300
+ type: "session_status_update",
1301
+ status: "idle",
1302
+ });
1077
1303
  }
1078
1304
  emitFastModeUpdateIfChanged(session, msg.fast_mode_state, msg.fast_mode_disabled_reason);
1079
1305
  return;
@@ -1087,7 +1313,8 @@ export function handleSdkMessage(session, message) {
1087
1313
  const preTokens = nonNegativeIntegerField(compactMetadata, "pre_tokens", "preTokens");
1088
1314
  const postTokens = nonNegativeIntegerField(compactMetadata, "post_tokens", "postTokens");
1089
1315
  const durationMs = nonNegativeIntegerField(compactMetadata, "duration_ms", "durationMs");
1090
- if ((trigger === "manual" || trigger === "auto") && preTokens !== undefined) {
1316
+ if ((trigger === "manual" || trigger === "auto") &&
1317
+ preTokens !== undefined) {
1091
1318
  emitSessionUpdate(session.sessionId, {
1092
1319
  type: "compaction_update",
1093
1320
  phase: "boundary",
@@ -1105,7 +1332,9 @@ export function handleSdkMessage(session, message) {
1105
1332
  emitSessionUpdate(session.sessionId, {
1106
1333
  type: "agent_message_chunk",
1107
1334
  content: { type: "text", text: content },
1108
- ...(sourceMessageUuid(msg) ? { source_message_uuid: sourceMessageUuid(msg) } : {}),
1335
+ ...(sourceMessageUuid(msg)
1336
+ ? { source_message_uuid: sourceMessageUuid(msg) }
1337
+ : {}),
1109
1338
  });
1110
1339
  }
1111
1340
  return;
@@ -1120,7 +1349,9 @@ export function handleSdkMessage(session, message) {
1120
1349
  session_id: session.sessionId,
1121
1350
  completion: {
1122
1351
  elicitation_id: elicitationId,
1123
- ...(typeof msg.mcp_server_name === "string" ? { server_name: msg.mcp_server_name } : {}),
1352
+ ...(typeof msg.mcp_server_name === "string"
1353
+ ? { server_name: msg.mcp_server_name }
1354
+ : {}),
1124
1355
  },
1125
1356
  });
1126
1357
  return;
@@ -1143,7 +1374,10 @@ export function handleSdkMessage(session, message) {
1143
1374
  if (type === "prompt_suggestion") {
1144
1375
  const suggestion = typeof msg.suggestion === "string" ? msg.suggestion.trim() : "";
1145
1376
  if (suggestion) {
1146
- emitSessionUpdate(session.sessionId, { type: "prompt_suggestion_update", suggestion });
1377
+ emitSessionUpdate(session.sessionId, {
1378
+ type: "prompt_suggestion_update",
1379
+ suggestion,
1380
+ });
1147
1381
  }
1148
1382
  return;
1149
1383
  }
@@ -1158,10 +1392,14 @@ export function handleSdkMessage(session, message) {
1158
1392
  }
1159
1393
  if (type === "auth_status") {
1160
1394
  const output = Array.isArray(msg.output)
1161
- ? msg.output.filter((entry) => typeof entry === "string").join("\n")
1395
+ ? msg.output
1396
+ .filter((entry) => typeof entry === "string")
1397
+ .join("\n")
1162
1398
  : "";
1163
1399
  const errorText = typeof msg.error === "string" ? msg.error : "";
1164
- const combined = [errorText, output].filter((entry) => entry.length > 0).join("\n");
1400
+ const combined = [errorText, output]
1401
+ .filter((entry) => entry.length > 0)
1402
+ .join("\n");
1165
1403
  if (combined && looksLikeAuthRequired(combined)) {
1166
1404
  emitAuthRequired(session, combined);
1167
1405
  }
@@ -1169,7 +1407,9 @@ export function handleSdkMessage(session, message) {
1169
1407
  }
1170
1408
  if (type === "stream_event") {
1171
1409
  if (msg.event && typeof msg.event === "object") {
1172
- const parentToolUseId = typeof msg.parent_tool_use_id === "string" ? msg.parent_tool_use_id : undefined;
1410
+ const parentToolUseId = typeof msg.parent_tool_use_id === "string"
1411
+ ? msg.parent_tool_use_id
1412
+ : undefined;
1173
1413
  handleStreamEvent(session, msg.event, parentToolUseId, sourceMessageUuid(msg));
1174
1414
  }
1175
1415
  return;
@@ -1179,7 +1419,9 @@ export function handleSdkMessage(session, message) {
1179
1419
  const toolName = typeof msg.tool_name === "string" ? msg.tool_name : "Tool";
1180
1420
  const parentToolUseId = typeof msg.parent_tool_use_id === "string" ? msg.parent_tool_use_id : "";
1181
1421
  const taskId = typeof msg.task_id === "string" ? msg.task_id : "";
1182
- const taskToolUseId = taskId ? session.taskToolUseIds.get(taskId) ?? "" : "";
1422
+ const taskToolUseId = taskId
1423
+ ? (session.taskToolUseIds.get(taskId) ?? "")
1424
+ : "";
1183
1425
  if (isHiddenToolUse(session, toolUseId, toolName)) {
1184
1426
  return;
1185
1427
  }
@@ -1204,7 +1446,9 @@ export function handleSdkMessage(session, message) {
1204
1446
  });
1205
1447
  if (resolvedToolUseId) {
1206
1448
  const hasSubagentRetry = Object.hasOwn(msg, "subagent_retry");
1207
- const subagentRetry = hasSubagentRetry ? buildSubagentRetryUpdate(msg) : null;
1449
+ const subagentRetry = hasSubagentRetry
1450
+ ? buildSubagentRetryUpdate(msg)
1451
+ : null;
1208
1452
  if (hasSubagentRetry && !subagentRetry) {
1209
1453
  bridgeLogger.warn({
1210
1454
  target: LOG_TARGETS.APP_TOOL,
@@ -1247,8 +1491,12 @@ export function handleSdkMessage(session, message) {
1247
1491
  if (type === "rate_limit_event") {
1248
1492
  const rateLimitInfo = asRecordOrNull(msg.rate_limit_info);
1249
1493
  const update = buildRateLimitUpdate(msg.rate_limit_info);
1250
- const rawIsUsingOverage = typeof rateLimitInfo?.isUsingOverage === "boolean" ? rateLimitInfo.isUsingOverage : undefined;
1251
- const rawOverageInUse = typeof rateLimitInfo?.overageInUse === "boolean" ? rateLimitInfo.overageInUse : undefined;
1494
+ const rawIsUsingOverage = typeof rateLimitInfo?.isUsingOverage === "boolean"
1495
+ ? rateLimitInfo.isUsingOverage
1496
+ : undefined;
1497
+ const rawOverageInUse = typeof rateLimitInfo?.overageInUse === "boolean"
1498
+ ? rateLimitInfo.overageInUse
1499
+ : undefined;
1252
1500
  if (rawIsUsingOverage !== undefined &&
1253
1501
  rawOverageInUse !== undefined &&
1254
1502
  rawIsUsingOverage !== rawOverageInUse) {
@@ -1271,11 +1519,17 @@ export function handleSdkMessage(session, message) {
1271
1519
  outcome: update ? "success" : "dropped",
1272
1520
  sessionId: session.sessionId,
1273
1521
  fields: {
1274
- raw_status: typeof rateLimitInfo?.status === "string" ? rateLimitInfo.status : undefined,
1275
- raw_rate_limit_type: typeof rateLimitInfo?.rateLimitType === "string" ? rateLimitInfo.rateLimitType : undefined,
1522
+ raw_status: typeof rateLimitInfo?.status === "string"
1523
+ ? rateLimitInfo.status
1524
+ : undefined,
1525
+ raw_rate_limit_type: typeof rateLimitInfo?.rateLimitType === "string"
1526
+ ? rateLimitInfo.rateLimitType
1527
+ : undefined,
1276
1528
  raw_utilization: numberField(rateLimitInfo ?? {}, "utilization"),
1277
1529
  raw_resets_at: numberField(rateLimitInfo ?? {}, "resetsAt"),
1278
- raw_overage_status: typeof rateLimitInfo?.overageStatus === "string" ? rateLimitInfo.overageStatus : undefined,
1530
+ raw_overage_status: typeof rateLimitInfo?.overageStatus === "string"
1531
+ ? rateLimitInfo.overageStatus
1532
+ : undefined,
1279
1533
  raw_overage_resets_at: numberField(rateLimitInfo ?? {}, "overageResetsAt"),
1280
1534
  raw_is_using_overage: rawIsUsingOverage,
1281
1535
  raw_overage_in_use: rawOverageInUse,
@@ -1306,6 +1560,10 @@ export function handleSdkMessage(session, message) {
1306
1560
  return;
1307
1561
  }
1308
1562
  if (type === "user") {
1563
+ const externalMessageUpdate = externalMessageUpdateFromSdkUser(msg);
1564
+ if (externalMessageUpdate) {
1565
+ emitSessionUpdate(session.sessionId, externalMessageUpdate);
1566
+ }
1309
1567
  const handledBlocks = handleUserToolResultBlocks(session, msg);
1310
1568
  const toolUseId = typeof msg.parent_tool_use_id === "string" ? msg.parent_tool_use_id : "";
1311
1569
  const rawToolUseResult = messageToolUseResult(msg);