@autohq/cli 0.1.449 → 0.1.450
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/dist/agent-bridge.js +248 -104
- package/dist/index.js +249 -104
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -30825,7 +30825,7 @@ Object.assign(lookup, {
|
|
|
30825
30825
|
// package.json
|
|
30826
30826
|
var package_default = {
|
|
30827
30827
|
name: "@autohq/cli",
|
|
30828
|
-
version: "0.1.
|
|
30828
|
+
version: "0.1.450",
|
|
30829
30829
|
license: "SEE LICENSE IN README.md",
|
|
30830
30830
|
publishConfig: {
|
|
30831
30831
|
access: "public"
|
|
@@ -71451,6 +71451,10 @@ function jsonRecordString2(value2, key) {
|
|
|
71451
71451
|
|
|
71452
71452
|
// src/commands/agent-bridge/harness/claude-code/projector.ts
|
|
71453
71453
|
var ClaudeCodeProjector = class {
|
|
71454
|
+
constructor(input = {}) {
|
|
71455
|
+
this.input = input;
|
|
71456
|
+
}
|
|
71457
|
+
input;
|
|
71454
71458
|
currentMessageId = null;
|
|
71455
71459
|
// The turn's UI message id. Claude emits a `message_start` per assistant
|
|
71456
71460
|
// message, but a tool-using turn spans several (message A with the tool call,
|
|
@@ -71469,13 +71473,17 @@ var ClaudeCodeProjector = class {
|
|
|
71469
71473
|
// real turn failure (FRA-3548). Cleared on every result and on the next
|
|
71470
71474
|
// message_start so a stale marker can never reclassify a later failure.
|
|
71471
71475
|
interruptMarkerSeen = false;
|
|
71472
|
-
project(message) {
|
|
71476
|
+
project(message, context = {}) {
|
|
71473
71477
|
if (isClaudeCodeInterruptMarker(message)) {
|
|
71474
71478
|
this.interruptMarkerSeen = true;
|
|
71475
71479
|
}
|
|
71476
71480
|
if (message.type === "stream_event") {
|
|
71477
71481
|
return this.projectStreamEvent(message);
|
|
71478
71482
|
}
|
|
71483
|
+
const interruptContext = {
|
|
71484
|
+
marker: this.interruptMarkerSeen,
|
|
71485
|
+
bridge: context.bridgeInterruptSettling === true
|
|
71486
|
+
};
|
|
71479
71487
|
const parsed = parseClaudeCodeStreamRecord(message);
|
|
71480
71488
|
const snapshotMessageId = assistantSnapshotMessageId(message);
|
|
71481
71489
|
const suppressStreamed = snapshotMessageId !== null && this.streamedMessageIds.has(snapshotMessageId);
|
|
@@ -71487,18 +71495,24 @@ var ClaudeCodeProjector = class {
|
|
|
71487
71495
|
return [];
|
|
71488
71496
|
}
|
|
71489
71497
|
return conversationProjectionToUiChunks(entry, {
|
|
71490
|
-
|
|
71498
|
+
interruptContext,
|
|
71499
|
+
emitDiagnostic: this.input.writeOutput
|
|
71491
71500
|
});
|
|
71492
71501
|
});
|
|
71493
71502
|
if (parsed.result) {
|
|
71494
71503
|
outputs.push(...this.endActiveParts(), ...this.finishActiveToolInputs());
|
|
71495
71504
|
this.currentMessageId = null;
|
|
71496
71505
|
this.activeResponseMessageId = null;
|
|
71497
|
-
|
|
71498
|
-
|
|
71499
|
-
|
|
71500
|
-
})
|
|
71506
|
+
const interrupted = this.isInterruptCancellation(
|
|
71507
|
+
parsed.result,
|
|
71508
|
+
interruptContext
|
|
71501
71509
|
);
|
|
71510
|
+
if (interrupted) {
|
|
71511
|
+
this.input.writeOutput?.(
|
|
71512
|
+
`agent_bridge_claude_result_interrupt_cancellation gate=${interruptGate(interruptContext)}`
|
|
71513
|
+
);
|
|
71514
|
+
}
|
|
71515
|
+
outputs.push(projectClaudeCodeResult(parsed.result, { interrupted }));
|
|
71502
71516
|
this.interruptMarkerSeen = false;
|
|
71503
71517
|
}
|
|
71504
71518
|
return outputs;
|
|
@@ -71508,9 +71522,11 @@ var ClaudeCodeProjector = class {
|
|
|
71508
71522
|
// surfaces as a diagnostic-only `error_during_execution`. Treating that as a
|
|
71509
71523
|
// turn failure fed the FRA-3548 redelivery loop (the bridge redelivered a
|
|
71510
71524
|
// message the SDK was actively answering), so a failed result bracketed by
|
|
71511
|
-
// the SDK's own
|
|
71512
|
-
|
|
71513
|
-
|
|
71525
|
+
// interrupt context — the SDK's own marker, or the session's knowledge that
|
|
71526
|
+
// a bridge interrupt is settling (which covers a missing or late marker) —
|
|
71527
|
+
// is classified as a cancellation instead.
|
|
71528
|
+
isInterruptCancellation(result, context) {
|
|
71529
|
+
return result.isError && (context.marker || context.bridge) && isClaudeCodeEdeDiagnosticOnlyError(result.errorMessage);
|
|
71514
71530
|
}
|
|
71515
71531
|
flushPendingAssistantMessages() {
|
|
71516
71532
|
const outputs = [
|
|
@@ -71631,7 +71647,8 @@ var ClaudeCodeProjector = class {
|
|
|
71631
71647
|
const messageChunks = this.assistantSnapshotMessageChunks(projections);
|
|
71632
71648
|
const rest = projections.filter((projection) => !isAssistantMessageOrToolCall(projection)).flatMap(
|
|
71633
71649
|
(projection) => conversationProjectionToUiChunks(projection, {
|
|
71634
|
-
|
|
71650
|
+
interruptContext: { marker: this.interruptMarkerSeen, bridge: false },
|
|
71651
|
+
emitDiagnostic: this.input.writeOutput
|
|
71635
71652
|
})
|
|
71636
71653
|
);
|
|
71637
71654
|
const last = messageChunks.at(-1);
|
|
@@ -71855,7 +71872,7 @@ function textContentFromDelta(delta) {
|
|
|
71855
71872
|
return null;
|
|
71856
71873
|
}
|
|
71857
71874
|
}
|
|
71858
|
-
function conversationProjectionToUiChunks(projection, options
|
|
71875
|
+
function conversationProjectionToUiChunks(projection, options) {
|
|
71859
71876
|
if (projection.role === "assistant" && projection.kind === "message") {
|
|
71860
71877
|
return messageContentChunks(projection);
|
|
71861
71878
|
}
|
|
@@ -71876,15 +71893,12 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
71876
71893
|
})
|
|
71877
71894
|
];
|
|
71878
71895
|
}
|
|
71879
|
-
const remapped = typeof part.output === "string" ? remapClaudeCodeInterruptToolResultErrorText(part.output, {
|
|
71880
|
-
interrupted: options.interrupted
|
|
71881
|
-
}) : null;
|
|
71882
71896
|
return [
|
|
71883
|
-
|
|
71884
|
-
|
|
71885
|
-
|
|
71886
|
-
|
|
71887
|
-
|
|
71897
|
+
toolResultErrorChunk(
|
|
71898
|
+
part.toolUseId ?? UNKNOWN_MESSAGE_ID,
|
|
71899
|
+
part.output,
|
|
71900
|
+
options
|
|
71901
|
+
)
|
|
71888
71902
|
];
|
|
71889
71903
|
});
|
|
71890
71904
|
}
|
|
@@ -71928,6 +71942,32 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
71928
71942
|
}
|
|
71929
71943
|
];
|
|
71930
71944
|
}
|
|
71945
|
+
function toolResultErrorChunk(toolCallId, output, options) {
|
|
71946
|
+
const context = options.interruptContext;
|
|
71947
|
+
const remapped = typeof output === "string" ? remapClaudeCodeInterruptToolResultErrorText(output, {
|
|
71948
|
+
interrupted: context.marker || context.bridge
|
|
71949
|
+
}) : null;
|
|
71950
|
+
if (remapped !== null) {
|
|
71951
|
+
options.emitDiagnostic?.(
|
|
71952
|
+
`agent_bridge_claude_tool_cancellation_remapped tool_use_id=${toolCallId} gate=${interruptGate(context)}`
|
|
71953
|
+
);
|
|
71954
|
+
} else if (typeof output === "string" && isClaudeCodePermissionDenialText(output)) {
|
|
71955
|
+
options.emitDiagnostic?.(
|
|
71956
|
+
`agent_bridge_claude_permission_denial_passthrough tool_use_id=${toolCallId}`
|
|
71957
|
+
);
|
|
71958
|
+
}
|
|
71959
|
+
return uiChunk({
|
|
71960
|
+
type: "tool-output-error",
|
|
71961
|
+
toolCallId,
|
|
71962
|
+
errorText: remapped ?? JSON.stringify(output)
|
|
71963
|
+
});
|
|
71964
|
+
}
|
|
71965
|
+
function interruptGate(context) {
|
|
71966
|
+
if (context.marker && context.bridge) {
|
|
71967
|
+
return "marker+bridge";
|
|
71968
|
+
}
|
|
71969
|
+
return context.marker ? "marker" : "bridge";
|
|
71970
|
+
}
|
|
71931
71971
|
function isAssistantMessageOrToolCall(projection) {
|
|
71932
71972
|
return projection.role === "assistant" && (projection.kind === "message" || projection.kind === "tool_call");
|
|
71933
71973
|
}
|
|
@@ -91972,7 +92012,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
|
|
|
91972
92012
|
|
|
91973
92013
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
91974
92014
|
var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
|
|
91975
|
-
var
|
|
92015
|
+
var CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS = 12e4;
|
|
91976
92016
|
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
91977
92017
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e4;
|
|
91978
92018
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
@@ -92048,16 +92088,33 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92048
92088
|
// flushed command id.
|
|
92049
92089
|
openTurnCommandIds = [];
|
|
92050
92090
|
// tool_use ids the assistant has emitted whose tool_result has not yet been
|
|
92051
|
-
// observed
|
|
92052
|
-
//
|
|
92091
|
+
// observed, with the name/detail needed to describe them in a cancellation
|
|
92092
|
+
// notice. A non-empty map means a tool call is in flight: interrupting now
|
|
92093
|
+
// would destroy its work and record a denial-worded cancellation, and
|
|
92094
|
+
// injecting now would append the new user message after an unresolved
|
|
92053
92095
|
// stop_reason=tool_use — the invalid transcript that trips Claude Code's
|
|
92054
92096
|
// ede_diagnostic and auto-restarts the session (FRA-3049).
|
|
92055
|
-
|
|
92056
|
-
// Incremented on every turn-terminal `result
|
|
92057
|
-
//
|
|
92058
|
-
// message lands only once the interrupted turn has settled its tool_use.
|
|
92097
|
+
pendingToolUses = /* @__PURE__ */ new Map();
|
|
92098
|
+
// Incremented on every turn-terminal `result`; the interrupt-timeout latch
|
|
92099
|
+
// compares against it to tell whether the same wedged turn is still running.
|
|
92059
92100
|
turnResultCount = 0;
|
|
92060
|
-
|
|
92101
|
+
// A steering message is waiting for the in-flight tool call to settle so the
|
|
92102
|
+
// turn can be interrupted at the tool boundary instead of mid-tool. Armed by
|
|
92103
|
+
// sendMessage, fired by the output pump when the pending tool_use set
|
|
92104
|
+
// drains, bounded by the budget timer below.
|
|
92105
|
+
toolBoundaryWait = null;
|
|
92106
|
+
// True from the moment a bridge-initiated interrupt control request fires
|
|
92107
|
+
// until the targeted turn emits its terminal result (or the stream ends).
|
|
92108
|
+
// Reported to the projector on every message so the SDK's denial-worded
|
|
92109
|
+
// cancellation records are classified as platform cancellations even though
|
|
92110
|
+
// the SDK's own interrupt marker arrives after them (probe-verified wire
|
|
92111
|
+
// order, 2026-07-13: tool_result → marker → error_during_execution result).
|
|
92112
|
+
interruptSettling = false;
|
|
92113
|
+
// Tool calls the SDK cancelled while a bridge-initiated interrupt was
|
|
92114
|
+
// settling. Consumed by the deferred flush: the injected message gets a
|
|
92115
|
+
// platform-cancellation notice naming this work so the model re-runs it
|
|
92116
|
+
// instead of treating the denial-worded tool_result as a human rejection.
|
|
92117
|
+
cancelledToolRuns = [];
|
|
92061
92118
|
// Memoized MCP-registration gate, keyed by the attached query. A runtime
|
|
92062
92119
|
// restart warms a brand-new session + query, so keying off the query object
|
|
92063
92120
|
// (rather than a session-lifetime flag) re-arms the gate on every restart:
|
|
@@ -92116,18 +92173,34 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92116
92173
|
delivery_mode: mode,
|
|
92117
92174
|
state: this.state.kind,
|
|
92118
92175
|
active_turn_count: this.activeTurnCount,
|
|
92119
|
-
pending_tool_use_count: this.
|
|
92176
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92120
92177
|
deferred_count: this.deferredMessages.length
|
|
92121
92178
|
});
|
|
92122
92179
|
if (mode === "deferred" && this.hasInterruptibleTurn()) {
|
|
92123
92180
|
this.deferredMessages.push({ text: message, commandIds });
|
|
92124
92181
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_deferred", {
|
|
92125
92182
|
active_turn_count: this.activeTurnCount,
|
|
92126
|
-
pending_tool_use_count: this.
|
|
92183
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92127
92184
|
deferred_count: this.deferredMessages.length
|
|
92128
92185
|
});
|
|
92129
92186
|
return;
|
|
92130
92187
|
}
|
|
92188
|
+
if (this.hasInterruptibleTurn() && this.hasInFlightToolUse()) {
|
|
92189
|
+
this.deferredMessages.push({ text: message, commandIds });
|
|
92190
|
+
this.armToolBoundaryWait();
|
|
92191
|
+
this.input.runtimeLogger?.info(
|
|
92192
|
+
"agent_bridge_claude_message_deferred_tool_boundary",
|
|
92193
|
+
{
|
|
92194
|
+
active_turn_count: this.activeTurnCount,
|
|
92195
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92196
|
+
pending_tools: [...this.pendingToolUses.values()].map(
|
|
92197
|
+
(tool) => tool.name
|
|
92198
|
+
),
|
|
92199
|
+
deferred_count: this.deferredMessages.length
|
|
92200
|
+
}
|
|
92201
|
+
);
|
|
92202
|
+
return;
|
|
92203
|
+
}
|
|
92131
92204
|
const interruption = await this.interruptActiveTurnBeforeMessage();
|
|
92132
92205
|
if (interruption === "defer" && this.hasInterruptibleTurn()) {
|
|
92133
92206
|
this.deferredMessages.push({ text: message, commandIds });
|
|
@@ -92135,7 +92208,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92135
92208
|
"agent_bridge_claude_message_deferred_after_interrupt_timeout",
|
|
92136
92209
|
{
|
|
92137
92210
|
active_turn_count: this.activeTurnCount,
|
|
92138
|
-
pending_tool_use_count: this.
|
|
92211
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92139
92212
|
deferred_count: this.deferredMessages.length
|
|
92140
92213
|
}
|
|
92141
92214
|
);
|
|
@@ -92148,7 +92221,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92148
92221
|
duration_ms: Date.now() - startedAt,
|
|
92149
92222
|
state: this.state.kind,
|
|
92150
92223
|
active_turn_count: this.activeTurnCount,
|
|
92151
|
-
pending_tool_use_count: this.
|
|
92224
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92152
92225
|
deferred_count: this.deferredMessages.length
|
|
92153
92226
|
});
|
|
92154
92227
|
}
|
|
@@ -92232,8 +92305,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92232
92305
|
}
|
|
92233
92306
|
this.state = { kind: "closed" };
|
|
92234
92307
|
this.activeTurnCount = 0;
|
|
92235
|
-
this.
|
|
92236
|
-
this.
|
|
92308
|
+
this.pendingToolUses.clear();
|
|
92309
|
+
this.cancelledToolRuns = [];
|
|
92310
|
+
this.interruptSettling = false;
|
|
92311
|
+
this.disarmToolBoundaryWait();
|
|
92237
92312
|
if (this.deferredMessages.length > 0) {
|
|
92238
92313
|
this.input.writeOutput?.(
|
|
92239
92314
|
`agent_bridge_claude_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
|
|
@@ -92324,19 +92399,21 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92324
92399
|
void (async () => {
|
|
92325
92400
|
try {
|
|
92326
92401
|
for await (const message of query) {
|
|
92402
|
+
const interruptSettling = this.interruptSettling;
|
|
92327
92403
|
this.trackToolUseLifecycle(message);
|
|
92328
|
-
let meta3;
|
|
92404
|
+
let meta3 = { interruptSettling };
|
|
92329
92405
|
if (isClaudeAgentTurnResult(message)) {
|
|
92330
92406
|
this.activeTurnCount = Math.max(0, this.activeTurnCount - 1);
|
|
92331
92407
|
meta3 = {
|
|
92408
|
+
interruptSettling,
|
|
92332
92409
|
consumedCommandIds: this.openTurnCommandIds.shift() ?? []
|
|
92333
92410
|
};
|
|
92334
|
-
this.
|
|
92411
|
+
this.pendingToolUses.clear();
|
|
92412
|
+
this.interruptSettling = false;
|
|
92335
92413
|
this.turnResultCount += 1;
|
|
92336
|
-
this.resolveTurnSettlement(true);
|
|
92337
92414
|
this.input.runtimeLogger?.info("agent_bridge_claude_turn_result", {
|
|
92338
92415
|
active_turn_count: this.activeTurnCount,
|
|
92339
|
-
pending_tool_use_count: this.
|
|
92416
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92340
92417
|
turn_result_count: this.turnResultCount,
|
|
92341
92418
|
deferred_count: this.deferredMessages.length,
|
|
92342
92419
|
consumed_command_ids: meta3.consumedCommandIds
|
|
@@ -92344,6 +92421,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92344
92421
|
if (this.activeTurnCount === 0) {
|
|
92345
92422
|
this.flushDeferredMessages();
|
|
92346
92423
|
}
|
|
92424
|
+
if (this.deferredMessages.length === 0) {
|
|
92425
|
+
this.cancelledToolRuns = [];
|
|
92426
|
+
}
|
|
92347
92427
|
}
|
|
92348
92428
|
const failure = probeClaudeAgentMessage(
|
|
92349
92429
|
message,
|
|
@@ -92368,8 +92448,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92368
92448
|
} finally {
|
|
92369
92449
|
this.activeTurnCount = 0;
|
|
92370
92450
|
this.openTurnCommandIds.length = 0;
|
|
92371
|
-
this.
|
|
92372
|
-
this.
|
|
92451
|
+
this.pendingToolUses.clear();
|
|
92452
|
+
this.interruptSettling = false;
|
|
92453
|
+
this.disarmToolBoundaryWait();
|
|
92373
92454
|
this.state = { kind: "closed" };
|
|
92374
92455
|
this.reportExit();
|
|
92375
92456
|
}
|
|
@@ -92386,7 +92467,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92386
92467
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_enqueued", {
|
|
92387
92468
|
state: this.state.kind,
|
|
92388
92469
|
active_turn_count: this.activeTurnCount,
|
|
92389
|
-
pending_tool_use_count: this.
|
|
92470
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92390
92471
|
deferred_count: this.deferredMessages.length
|
|
92391
92472
|
});
|
|
92392
92473
|
void this.ensureRunningQuery().catch((error51) => {
|
|
@@ -92399,75 +92480,105 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92399
92480
|
return this.activeTurnCount > 0 && this.state.kind === "running";
|
|
92400
92481
|
}
|
|
92401
92482
|
// True while the assistant has an emitted tool_use with no matching
|
|
92402
|
-
// tool_result yet — the window where an immediate interrupt would
|
|
92483
|
+
// tool_result yet — the window where an immediate interrupt would cancel
|
|
92484
|
+
// real tool work, and where an immediate injection would strand an
|
|
92403
92485
|
// unresolved stop_reason=tool_use ahead of the injected user message.
|
|
92404
92486
|
hasInFlightToolUse() {
|
|
92405
|
-
return this.
|
|
92487
|
+
return this.pendingToolUses.size > 0;
|
|
92406
92488
|
}
|
|
92407
92489
|
// Track tool_use/tool_result pairs as they stream so hasInFlightToolUse()
|
|
92408
92490
|
// reflects the live transcript. A tool_use may appear first as a streaming
|
|
92409
92491
|
// content block before the full assistant message is available; the matching
|
|
92410
92492
|
// tool_result closes it; the turn's terminal result clears any remainder.
|
|
92493
|
+
// Two side jobs ride on the same observation point:
|
|
92494
|
+
// - a denial-worded error tool_result arriving while a bridge interrupt is
|
|
92495
|
+
// settling is that interrupt's cancellation of the tool — record it so the
|
|
92496
|
+
// flushed message can tell the model to re-run the cancelled work;
|
|
92497
|
+
// - a tool_result that drains the pending set is the tool boundary an armed
|
|
92498
|
+
// steering message has been waiting for — interrupt the turn now, while no
|
|
92499
|
+
// tool work is at risk.
|
|
92411
92500
|
trackToolUseLifecycle(message) {
|
|
92412
|
-
for (const
|
|
92413
|
-
this.
|
|
92501
|
+
for (const entry of toolUseEntries(message)) {
|
|
92502
|
+
this.pendingToolUses.set(entry.id, {
|
|
92503
|
+
name: entry.name,
|
|
92504
|
+
detail: entry.detail
|
|
92505
|
+
});
|
|
92414
92506
|
}
|
|
92415
|
-
|
|
92416
|
-
|
|
92507
|
+
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
92508
|
+
for (const result of toolResultEntries(message)) {
|
|
92509
|
+
const pending = this.pendingToolUses.get(result.id);
|
|
92510
|
+
this.pendingToolUses.delete(result.id);
|
|
92511
|
+
if (pending && this.interruptSettling && result.isError && result.text !== null && isClaudeCodePermissionDenialText(result.text)) {
|
|
92512
|
+
this.cancelledToolRuns.push(pending);
|
|
92513
|
+
this.input.writeOutput?.(
|
|
92514
|
+
`agent_bridge_claude_tool_cancellation_observed tool=${pending.name}`
|
|
92515
|
+
);
|
|
92516
|
+
}
|
|
92517
|
+
}
|
|
92518
|
+
if (hadInFlightToolUse && !this.hasInFlightToolUse()) {
|
|
92519
|
+
this.fireToolBoundaryInterrupt();
|
|
92417
92520
|
}
|
|
92418
92521
|
}
|
|
92419
|
-
//
|
|
92420
|
-
//
|
|
92421
|
-
//
|
|
92422
|
-
//
|
|
92423
|
-
//
|
|
92424
|
-
|
|
92425
|
-
if (this.
|
|
92426
|
-
return
|
|
92522
|
+
// The pending tool_use set just drained mid-turn. If a steering message is
|
|
92523
|
+
// waiting on that boundary, interrupt the turn now: nothing is executing, so
|
|
92524
|
+
// the cancellation costs only the model's remaining reasoning, and the
|
|
92525
|
+
// turn's terminal result flushes the message. Fire-and-forget — the flush at
|
|
92526
|
+
// the turn result owns delivery whether or not this interrupt lands.
|
|
92527
|
+
fireToolBoundaryInterrupt() {
|
|
92528
|
+
if (!this.toolBoundaryWait || this.deferredMessages.length === 0 || !this.hasInterruptibleTurn()) {
|
|
92529
|
+
return;
|
|
92427
92530
|
}
|
|
92428
|
-
|
|
92429
|
-
|
|
92430
|
-
|
|
92431
|
-
|
|
92432
|
-
|
|
92433
|
-
|
|
92434
|
-
|
|
92435
|
-
|
|
92436
|
-
|
|
92437
|
-
|
|
92438
|
-
|
|
92439
|
-
|
|
92440
|
-
|
|
92441
|
-
|
|
92442
|
-
|
|
92443
|
-
|
|
92444
|
-
|
|
92445
|
-
|
|
92531
|
+
this.disarmToolBoundaryWait();
|
|
92532
|
+
this.input.writeOutput?.(
|
|
92533
|
+
`agent_bridge_claude_tool_boundary_interrupt deferred_count=${this.deferredMessages.length}`
|
|
92534
|
+
);
|
|
92535
|
+
void this.interruptActiveTurn();
|
|
92536
|
+
}
|
|
92537
|
+
// Bound the tool-boundary wait: past the budget the steering message is
|
|
92538
|
+
// judged more urgent than the in-flight tool, which is cancelled mid-run.
|
|
92539
|
+
// The cancellation is observed by trackToolUseLifecycle and reported to the
|
|
92540
|
+
// model in the flushed message's platform notice.
|
|
92541
|
+
armToolBoundaryWait() {
|
|
92542
|
+
if (this.toolBoundaryWait) {
|
|
92543
|
+
return;
|
|
92544
|
+
}
|
|
92545
|
+
const timer = setTimeout(() => {
|
|
92546
|
+
this.toolBoundaryWait = null;
|
|
92547
|
+
if (!this.hasInterruptibleTurn() || this.deferredMessages.length === 0) {
|
|
92548
|
+
return;
|
|
92549
|
+
}
|
|
92550
|
+
this.input.writeOutput?.(
|
|
92551
|
+
`agent_bridge_claude_tool_boundary_wait_timeout pending_tools=${[
|
|
92552
|
+
...this.pendingToolUses.values()
|
|
92553
|
+
].map((tool) => tool.name).join(",")} deferred_count=${this.deferredMessages.length}`
|
|
92446
92554
|
);
|
|
92447
|
-
|
|
92448
|
-
|
|
92449
|
-
|
|
92555
|
+
void this.interruptActiveTurn();
|
|
92556
|
+
}, CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS);
|
|
92557
|
+
timer.unref?.();
|
|
92558
|
+
this.toolBoundaryWait = { timer };
|
|
92450
92559
|
}
|
|
92451
|
-
|
|
92452
|
-
if (this.
|
|
92560
|
+
disarmToolBoundaryWait() {
|
|
92561
|
+
if (!this.toolBoundaryWait) {
|
|
92453
92562
|
return;
|
|
92454
92563
|
}
|
|
92455
|
-
|
|
92456
|
-
this.
|
|
92457
|
-
for (const waiter of waiters) {
|
|
92458
|
-
waiter(settled);
|
|
92459
|
-
}
|
|
92564
|
+
clearTimeout(this.toolBoundaryWait.timer);
|
|
92565
|
+
this.toolBoundaryWait = null;
|
|
92460
92566
|
}
|
|
92461
92567
|
flushDeferredMessages() {
|
|
92462
92568
|
if (this.deferredMessages.length === 0) {
|
|
92463
92569
|
return;
|
|
92464
92570
|
}
|
|
92465
92571
|
const pending = this.deferredMessages.splice(0);
|
|
92572
|
+
const cancelledToolRuns = this.cancelledToolRuns.splice(0);
|
|
92573
|
+
this.disarmToolBoundaryWait();
|
|
92466
92574
|
this.input.writeOutput?.(
|
|
92467
|
-
`agent_bridge_claude_deferred_flush count=${pending.length}`
|
|
92575
|
+
`agent_bridge_claude_deferred_flush count=${pending.length} cancelled_tool_count=${cancelledToolRuns.length}`
|
|
92468
92576
|
);
|
|
92577
|
+
const text2 = pending.map((entry) => entry.text).join("\n\n");
|
|
92469
92578
|
this.enqueueUserMessage(
|
|
92470
|
-
|
|
92579
|
+
cancelledToolRuns.length > 0 ? `${text2}
|
|
92580
|
+
|
|
92581
|
+
${cancelledToolPlatformNotice(cancelledToolRuns)}` : text2,
|
|
92471
92582
|
pending.flatMap((entry) => entry.commandIds)
|
|
92472
92583
|
);
|
|
92473
92584
|
}
|
|
@@ -92488,11 +92599,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92488
92599
|
return "proceed";
|
|
92489
92600
|
}
|
|
92490
92601
|
const query = this.state.query;
|
|
92491
|
-
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
92492
92602
|
const settlementBaseline = this.turnResultCount;
|
|
92493
92603
|
const startedAt = Date.now();
|
|
92494
92604
|
this.input.writeOutput?.(
|
|
92495
|
-
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${
|
|
92605
|
+
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${this.hasInFlightToolUse()}`
|
|
92496
92606
|
);
|
|
92497
92607
|
const interruptPromise = (async () => {
|
|
92498
92608
|
const ack = await this.requestInterruptAck(query, startedAt);
|
|
@@ -92500,16 +92610,6 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92500
92610
|
this.interruptTimeoutTurn = settlementBaseline;
|
|
92501
92611
|
return "defer";
|
|
92502
92612
|
}
|
|
92503
|
-
if (hadInFlightToolUse) {
|
|
92504
|
-
const settle = await this.awaitTurnSettlement(
|
|
92505
|
-
settlementBaseline,
|
|
92506
|
-
startedAt
|
|
92507
|
-
);
|
|
92508
|
-
if (settle === "timeout") {
|
|
92509
|
-
this.interruptTimeoutTurn = settlementBaseline;
|
|
92510
|
-
return "defer";
|
|
92511
|
-
}
|
|
92512
|
-
}
|
|
92513
92613
|
return "proceed";
|
|
92514
92614
|
})();
|
|
92515
92615
|
this.interruptInFlight = interruptPromise;
|
|
@@ -92546,6 +92646,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92546
92646
|
);
|
|
92547
92647
|
}, CLAUDE_INTERRUPT_ACK_TIMEOUT_MS);
|
|
92548
92648
|
timer.unref?.();
|
|
92649
|
+
this.interruptSettling = true;
|
|
92549
92650
|
query.interrupt().then(
|
|
92550
92651
|
() => {
|
|
92551
92652
|
if (done) {
|
|
@@ -92902,10 +93003,10 @@ function claudeAgentUserMessage(message) {
|
|
|
92902
93003
|
function isClaudeAgentTurnResult(message) {
|
|
92903
93004
|
return message.type === "result";
|
|
92904
93005
|
}
|
|
92905
|
-
function
|
|
93006
|
+
function toolUseEntries(message) {
|
|
92906
93007
|
if (message.type === "assistant") {
|
|
92907
93008
|
return contentBlocks2(message.message.content).flatMap(
|
|
92908
|
-
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [block2
|
|
93009
|
+
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [toolUseEntryFromBlock(block2)] : []
|
|
92909
93010
|
);
|
|
92910
93011
|
}
|
|
92911
93012
|
if (message.type !== "stream_event") {
|
|
@@ -92916,15 +93017,53 @@ function toolUseIds(message) {
|
|
|
92916
93017
|
return [];
|
|
92917
93018
|
}
|
|
92918
93019
|
const block = event.content_block;
|
|
92919
|
-
return block.type === "tool_use" && typeof block.id === "string" ? [block
|
|
93020
|
+
return block.type === "tool_use" && typeof block.id === "string" ? [toolUseEntryFromBlock(block)] : [];
|
|
92920
93021
|
}
|
|
92921
|
-
function
|
|
93022
|
+
function toolUseEntryFromBlock(block) {
|
|
93023
|
+
return {
|
|
93024
|
+
id: String(block.id),
|
|
93025
|
+
name: typeof block.name === "string" ? block.name : "unknown_tool",
|
|
93026
|
+
detail: toolUseDetail(block.input)
|
|
93027
|
+
};
|
|
93028
|
+
}
|
|
93029
|
+
function toolUseDetail(input) {
|
|
93030
|
+
if (input === void 0 || input === null) {
|
|
93031
|
+
return "";
|
|
93032
|
+
}
|
|
93033
|
+
let text2;
|
|
93034
|
+
try {
|
|
93035
|
+
text2 = JSON.stringify(input);
|
|
93036
|
+
} catch {
|
|
93037
|
+
return "";
|
|
93038
|
+
}
|
|
93039
|
+
if (!text2 || text2 === "{}") {
|
|
93040
|
+
return "";
|
|
93041
|
+
}
|
|
93042
|
+
return text2.length > 160 ? `${text2.slice(0, 160)}\u2026` : text2;
|
|
93043
|
+
}
|
|
93044
|
+
function toolResultEntries(message) {
|
|
92922
93045
|
if (message.type !== "user") {
|
|
92923
93046
|
return [];
|
|
92924
93047
|
}
|
|
92925
93048
|
return contentBlocks2(message.message.content).flatMap(
|
|
92926
|
-
(block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [
|
|
93049
|
+
(block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [
|
|
93050
|
+
{
|
|
93051
|
+
id: block.tool_use_id,
|
|
93052
|
+
isError: block.is_error === true,
|
|
93053
|
+
text: typeof block.content === "string" ? block.content : null
|
|
93054
|
+
}
|
|
93055
|
+
] : []
|
|
93056
|
+
);
|
|
93057
|
+
}
|
|
93058
|
+
function cancelledToolPlatformNotice(cancelled) {
|
|
93059
|
+
const lines = cancelled.map(
|
|
93060
|
+
(tool) => `- ${tool.name}${tool.detail ? ` ${tool.detail}` : ""}`
|
|
92927
93061
|
);
|
|
93062
|
+
return [
|
|
93063
|
+
"[Auto platform notice] To deliver the message above, the platform cancelled the following in-flight tool call(s) mid-execution:",
|
|
93064
|
+
...lines,
|
|
93065
|
+
"This was a platform-initiated cancellation for message delivery, NOT a rejection or permission denial by the user \u2014 ignore any tool result saying the user doesn't want to proceed. Re-run or resume that tool work if it is still needed once you have applied the message."
|
|
93066
|
+
].join("\n");
|
|
92928
93067
|
}
|
|
92929
93068
|
function contentBlocks2(content) {
|
|
92930
93069
|
if (!Array.isArray(content)) {
|
|
@@ -92944,6 +93083,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
92944
93083
|
this.input = input;
|
|
92945
93084
|
this.claudeConfig = input.claude;
|
|
92946
93085
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
93086
|
+
this.projector = new ClaudeCodeProjector({
|
|
93087
|
+
writeOutput: input.writeOutput
|
|
93088
|
+
});
|
|
92947
93089
|
this.readState = input.readState ? new ClaudeReadStateTracker(input.readState) : null;
|
|
92948
93090
|
}
|
|
92949
93091
|
input;
|
|
@@ -92965,7 +93107,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
92965
93107
|
inFlightMessageCommands = /* @__PURE__ */ new Map();
|
|
92966
93108
|
pendingQuestions = /* @__PURE__ */ new Map();
|
|
92967
93109
|
outputBuffer;
|
|
92968
|
-
projector
|
|
93110
|
+
projector;
|
|
92969
93111
|
readState;
|
|
92970
93112
|
livenessTicker = null;
|
|
92971
93113
|
// -----------------------------------------------------------------------------
|
|
@@ -93346,7 +93488,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
93346
93488
|
this.trackReadState(activeContext, message);
|
|
93347
93489
|
let projections;
|
|
93348
93490
|
try {
|
|
93349
|
-
projections = this.projector.project(message
|
|
93491
|
+
projections = this.projector.project(message, {
|
|
93492
|
+
bridgeInterruptSettling: meta3?.interruptSettling === true
|
|
93493
|
+
});
|
|
93350
93494
|
} catch (error51) {
|
|
93351
93495
|
this.input.writeOutput?.(
|
|
93352
93496
|
`agent_bridge_claude_parse_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
|
package/dist/index.js
CHANGED
|
@@ -49211,7 +49211,7 @@ var init_package = __esm({
|
|
|
49211
49211
|
"package.json"() {
|
|
49212
49212
|
package_default = {
|
|
49213
49213
|
name: "@autohq/cli",
|
|
49214
|
-
version: "0.1.
|
|
49214
|
+
version: "0.1.450",
|
|
49215
49215
|
license: "SEE LICENSE IN README.md",
|
|
49216
49216
|
publishConfig: {
|
|
49217
49217
|
access: "public"
|
|
@@ -62052,6 +62052,10 @@ function jsonRecordString2(value, key) {
|
|
|
62052
62052
|
// src/commands/agent-bridge/harness/claude-code/projector.ts
|
|
62053
62053
|
init_src();
|
|
62054
62054
|
var ClaudeCodeProjector = class {
|
|
62055
|
+
constructor(input = {}) {
|
|
62056
|
+
this.input = input;
|
|
62057
|
+
}
|
|
62058
|
+
input;
|
|
62055
62059
|
currentMessageId = null;
|
|
62056
62060
|
// The turn's UI message id. Claude emits a `message_start` per assistant
|
|
62057
62061
|
// message, but a tool-using turn spans several (message A with the tool call,
|
|
@@ -62070,13 +62074,17 @@ var ClaudeCodeProjector = class {
|
|
|
62070
62074
|
// real turn failure (FRA-3548). Cleared on every result and on the next
|
|
62071
62075
|
// message_start so a stale marker can never reclassify a later failure.
|
|
62072
62076
|
interruptMarkerSeen = false;
|
|
62073
|
-
project(message) {
|
|
62077
|
+
project(message, context = {}) {
|
|
62074
62078
|
if (isClaudeCodeInterruptMarker(message)) {
|
|
62075
62079
|
this.interruptMarkerSeen = true;
|
|
62076
62080
|
}
|
|
62077
62081
|
if (message.type === "stream_event") {
|
|
62078
62082
|
return this.projectStreamEvent(message);
|
|
62079
62083
|
}
|
|
62084
|
+
const interruptContext = {
|
|
62085
|
+
marker: this.interruptMarkerSeen,
|
|
62086
|
+
bridge: context.bridgeInterruptSettling === true
|
|
62087
|
+
};
|
|
62080
62088
|
const parsed = parseClaudeCodeStreamRecord(message);
|
|
62081
62089
|
const snapshotMessageId = assistantSnapshotMessageId(message);
|
|
62082
62090
|
const suppressStreamed = snapshotMessageId !== null && this.streamedMessageIds.has(snapshotMessageId);
|
|
@@ -62088,18 +62096,24 @@ var ClaudeCodeProjector = class {
|
|
|
62088
62096
|
return [];
|
|
62089
62097
|
}
|
|
62090
62098
|
return conversationProjectionToUiChunks(entry, {
|
|
62091
|
-
|
|
62099
|
+
interruptContext,
|
|
62100
|
+
emitDiagnostic: this.input.writeOutput
|
|
62092
62101
|
});
|
|
62093
62102
|
});
|
|
62094
62103
|
if (parsed.result) {
|
|
62095
62104
|
outputs.push(...this.endActiveParts(), ...this.finishActiveToolInputs());
|
|
62096
62105
|
this.currentMessageId = null;
|
|
62097
62106
|
this.activeResponseMessageId = null;
|
|
62098
|
-
|
|
62099
|
-
|
|
62100
|
-
|
|
62101
|
-
})
|
|
62107
|
+
const interrupted = this.isInterruptCancellation(
|
|
62108
|
+
parsed.result,
|
|
62109
|
+
interruptContext
|
|
62102
62110
|
);
|
|
62111
|
+
if (interrupted) {
|
|
62112
|
+
this.input.writeOutput?.(
|
|
62113
|
+
`agent_bridge_claude_result_interrupt_cancellation gate=${interruptGate(interruptContext)}`
|
|
62114
|
+
);
|
|
62115
|
+
}
|
|
62116
|
+
outputs.push(projectClaudeCodeResult(parsed.result, { interrupted }));
|
|
62103
62117
|
this.interruptMarkerSeen = false;
|
|
62104
62118
|
}
|
|
62105
62119
|
return outputs;
|
|
@@ -62109,9 +62123,11 @@ var ClaudeCodeProjector = class {
|
|
|
62109
62123
|
// surfaces as a diagnostic-only `error_during_execution`. Treating that as a
|
|
62110
62124
|
// turn failure fed the FRA-3548 redelivery loop (the bridge redelivered a
|
|
62111
62125
|
// message the SDK was actively answering), so a failed result bracketed by
|
|
62112
|
-
// the SDK's own
|
|
62113
|
-
|
|
62114
|
-
|
|
62126
|
+
// interrupt context — the SDK's own marker, or the session's knowledge that
|
|
62127
|
+
// a bridge interrupt is settling (which covers a missing or late marker) —
|
|
62128
|
+
// is classified as a cancellation instead.
|
|
62129
|
+
isInterruptCancellation(result, context) {
|
|
62130
|
+
return result.isError && (context.marker || context.bridge) && isClaudeCodeEdeDiagnosticOnlyError(result.errorMessage);
|
|
62115
62131
|
}
|
|
62116
62132
|
flushPendingAssistantMessages() {
|
|
62117
62133
|
const outputs = [
|
|
@@ -62232,7 +62248,8 @@ var ClaudeCodeProjector = class {
|
|
|
62232
62248
|
const messageChunks = this.assistantSnapshotMessageChunks(projections);
|
|
62233
62249
|
const rest = projections.filter((projection) => !isAssistantMessageOrToolCall(projection)).flatMap(
|
|
62234
62250
|
(projection) => conversationProjectionToUiChunks(projection, {
|
|
62235
|
-
|
|
62251
|
+
interruptContext: { marker: this.interruptMarkerSeen, bridge: false },
|
|
62252
|
+
emitDiagnostic: this.input.writeOutput
|
|
62236
62253
|
})
|
|
62237
62254
|
);
|
|
62238
62255
|
const last = messageChunks.at(-1);
|
|
@@ -62456,7 +62473,7 @@ function textContentFromDelta(delta) {
|
|
|
62456
62473
|
return null;
|
|
62457
62474
|
}
|
|
62458
62475
|
}
|
|
62459
|
-
function conversationProjectionToUiChunks(projection, options
|
|
62476
|
+
function conversationProjectionToUiChunks(projection, options) {
|
|
62460
62477
|
if (projection.role === "assistant" && projection.kind === "message") {
|
|
62461
62478
|
return messageContentChunks(projection);
|
|
62462
62479
|
}
|
|
@@ -62477,15 +62494,12 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
62477
62494
|
})
|
|
62478
62495
|
];
|
|
62479
62496
|
}
|
|
62480
|
-
const remapped = typeof part.output === "string" ? remapClaudeCodeInterruptToolResultErrorText(part.output, {
|
|
62481
|
-
interrupted: options.interrupted
|
|
62482
|
-
}) : null;
|
|
62483
62497
|
return [
|
|
62484
|
-
|
|
62485
|
-
|
|
62486
|
-
|
|
62487
|
-
|
|
62488
|
-
|
|
62498
|
+
toolResultErrorChunk(
|
|
62499
|
+
part.toolUseId ?? UNKNOWN_MESSAGE_ID,
|
|
62500
|
+
part.output,
|
|
62501
|
+
options
|
|
62502
|
+
)
|
|
62489
62503
|
];
|
|
62490
62504
|
});
|
|
62491
62505
|
}
|
|
@@ -62529,6 +62543,32 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
62529
62543
|
}
|
|
62530
62544
|
];
|
|
62531
62545
|
}
|
|
62546
|
+
function toolResultErrorChunk(toolCallId, output, options) {
|
|
62547
|
+
const context = options.interruptContext;
|
|
62548
|
+
const remapped = typeof output === "string" ? remapClaudeCodeInterruptToolResultErrorText(output, {
|
|
62549
|
+
interrupted: context.marker || context.bridge
|
|
62550
|
+
}) : null;
|
|
62551
|
+
if (remapped !== null) {
|
|
62552
|
+
options.emitDiagnostic?.(
|
|
62553
|
+
`agent_bridge_claude_tool_cancellation_remapped tool_use_id=${toolCallId} gate=${interruptGate(context)}`
|
|
62554
|
+
);
|
|
62555
|
+
} else if (typeof output === "string" && isClaudeCodePermissionDenialText(output)) {
|
|
62556
|
+
options.emitDiagnostic?.(
|
|
62557
|
+
`agent_bridge_claude_permission_denial_passthrough tool_use_id=${toolCallId}`
|
|
62558
|
+
);
|
|
62559
|
+
}
|
|
62560
|
+
return uiChunk({
|
|
62561
|
+
type: "tool-output-error",
|
|
62562
|
+
toolCallId,
|
|
62563
|
+
errorText: remapped ?? JSON.stringify(output)
|
|
62564
|
+
});
|
|
62565
|
+
}
|
|
62566
|
+
function interruptGate(context) {
|
|
62567
|
+
if (context.marker && context.bridge) {
|
|
62568
|
+
return "marker+bridge";
|
|
62569
|
+
}
|
|
62570
|
+
return context.marker ? "marker" : "bridge";
|
|
62571
|
+
}
|
|
62532
62572
|
function isAssistantMessageOrToolCall(projection) {
|
|
62533
62573
|
return projection.role === "assistant" && (projection.kind === "message" || projection.kind === "tool_call");
|
|
62534
62574
|
}
|
|
@@ -62807,6 +62847,7 @@ function parseReadStateRecord(raw) {
|
|
|
62807
62847
|
}
|
|
62808
62848
|
|
|
62809
62849
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
62850
|
+
init_src();
|
|
62810
62851
|
import {
|
|
62811
62852
|
startup as startupClaudeAgent
|
|
62812
62853
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
@@ -63001,7 +63042,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
|
|
|
63001
63042
|
|
|
63002
63043
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
63003
63044
|
var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
|
|
63004
|
-
var
|
|
63045
|
+
var CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS = 12e4;
|
|
63005
63046
|
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
63006
63047
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e4;
|
|
63007
63048
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
@@ -63077,16 +63118,33 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63077
63118
|
// flushed command id.
|
|
63078
63119
|
openTurnCommandIds = [];
|
|
63079
63120
|
// tool_use ids the assistant has emitted whose tool_result has not yet been
|
|
63080
|
-
// observed
|
|
63081
|
-
//
|
|
63121
|
+
// observed, with the name/detail needed to describe them in a cancellation
|
|
63122
|
+
// notice. A non-empty map means a tool call is in flight: interrupting now
|
|
63123
|
+
// would destroy its work and record a denial-worded cancellation, and
|
|
63124
|
+
// injecting now would append the new user message after an unresolved
|
|
63082
63125
|
// stop_reason=tool_use — the invalid transcript that trips Claude Code's
|
|
63083
63126
|
// ede_diagnostic and auto-restarts the session (FRA-3049).
|
|
63084
|
-
|
|
63085
|
-
// Incremented on every turn-terminal `result
|
|
63086
|
-
//
|
|
63087
|
-
// message lands only once the interrupted turn has settled its tool_use.
|
|
63127
|
+
pendingToolUses = /* @__PURE__ */ new Map();
|
|
63128
|
+
// Incremented on every turn-terminal `result`; the interrupt-timeout latch
|
|
63129
|
+
// compares against it to tell whether the same wedged turn is still running.
|
|
63088
63130
|
turnResultCount = 0;
|
|
63089
|
-
|
|
63131
|
+
// A steering message is waiting for the in-flight tool call to settle so the
|
|
63132
|
+
// turn can be interrupted at the tool boundary instead of mid-tool. Armed by
|
|
63133
|
+
// sendMessage, fired by the output pump when the pending tool_use set
|
|
63134
|
+
// drains, bounded by the budget timer below.
|
|
63135
|
+
toolBoundaryWait = null;
|
|
63136
|
+
// True from the moment a bridge-initiated interrupt control request fires
|
|
63137
|
+
// until the targeted turn emits its terminal result (or the stream ends).
|
|
63138
|
+
// Reported to the projector on every message so the SDK's denial-worded
|
|
63139
|
+
// cancellation records are classified as platform cancellations even though
|
|
63140
|
+
// the SDK's own interrupt marker arrives after them (probe-verified wire
|
|
63141
|
+
// order, 2026-07-13: tool_result → marker → error_during_execution result).
|
|
63142
|
+
interruptSettling = false;
|
|
63143
|
+
// Tool calls the SDK cancelled while a bridge-initiated interrupt was
|
|
63144
|
+
// settling. Consumed by the deferred flush: the injected message gets a
|
|
63145
|
+
// platform-cancellation notice naming this work so the model re-runs it
|
|
63146
|
+
// instead of treating the denial-worded tool_result as a human rejection.
|
|
63147
|
+
cancelledToolRuns = [];
|
|
63090
63148
|
// Memoized MCP-registration gate, keyed by the attached query. A runtime
|
|
63091
63149
|
// restart warms a brand-new session + query, so keying off the query object
|
|
63092
63150
|
// (rather than a session-lifetime flag) re-arms the gate on every restart:
|
|
@@ -63145,18 +63203,34 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63145
63203
|
delivery_mode: mode,
|
|
63146
63204
|
state: this.state.kind,
|
|
63147
63205
|
active_turn_count: this.activeTurnCount,
|
|
63148
|
-
pending_tool_use_count: this.
|
|
63206
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63149
63207
|
deferred_count: this.deferredMessages.length
|
|
63150
63208
|
});
|
|
63151
63209
|
if (mode === "deferred" && this.hasInterruptibleTurn()) {
|
|
63152
63210
|
this.deferredMessages.push({ text: message, commandIds });
|
|
63153
63211
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_deferred", {
|
|
63154
63212
|
active_turn_count: this.activeTurnCount,
|
|
63155
|
-
pending_tool_use_count: this.
|
|
63213
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63156
63214
|
deferred_count: this.deferredMessages.length
|
|
63157
63215
|
});
|
|
63158
63216
|
return;
|
|
63159
63217
|
}
|
|
63218
|
+
if (this.hasInterruptibleTurn() && this.hasInFlightToolUse()) {
|
|
63219
|
+
this.deferredMessages.push({ text: message, commandIds });
|
|
63220
|
+
this.armToolBoundaryWait();
|
|
63221
|
+
this.input.runtimeLogger?.info(
|
|
63222
|
+
"agent_bridge_claude_message_deferred_tool_boundary",
|
|
63223
|
+
{
|
|
63224
|
+
active_turn_count: this.activeTurnCount,
|
|
63225
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63226
|
+
pending_tools: [...this.pendingToolUses.values()].map(
|
|
63227
|
+
(tool) => tool.name
|
|
63228
|
+
),
|
|
63229
|
+
deferred_count: this.deferredMessages.length
|
|
63230
|
+
}
|
|
63231
|
+
);
|
|
63232
|
+
return;
|
|
63233
|
+
}
|
|
63160
63234
|
const interruption = await this.interruptActiveTurnBeforeMessage();
|
|
63161
63235
|
if (interruption === "defer" && this.hasInterruptibleTurn()) {
|
|
63162
63236
|
this.deferredMessages.push({ text: message, commandIds });
|
|
@@ -63164,7 +63238,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63164
63238
|
"agent_bridge_claude_message_deferred_after_interrupt_timeout",
|
|
63165
63239
|
{
|
|
63166
63240
|
active_turn_count: this.activeTurnCount,
|
|
63167
|
-
pending_tool_use_count: this.
|
|
63241
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63168
63242
|
deferred_count: this.deferredMessages.length
|
|
63169
63243
|
}
|
|
63170
63244
|
);
|
|
@@ -63177,7 +63251,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63177
63251
|
duration_ms: Date.now() - startedAt,
|
|
63178
63252
|
state: this.state.kind,
|
|
63179
63253
|
active_turn_count: this.activeTurnCount,
|
|
63180
|
-
pending_tool_use_count: this.
|
|
63254
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63181
63255
|
deferred_count: this.deferredMessages.length
|
|
63182
63256
|
});
|
|
63183
63257
|
}
|
|
@@ -63261,8 +63335,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63261
63335
|
}
|
|
63262
63336
|
this.state = { kind: "closed" };
|
|
63263
63337
|
this.activeTurnCount = 0;
|
|
63264
|
-
this.
|
|
63265
|
-
this.
|
|
63338
|
+
this.pendingToolUses.clear();
|
|
63339
|
+
this.cancelledToolRuns = [];
|
|
63340
|
+
this.interruptSettling = false;
|
|
63341
|
+
this.disarmToolBoundaryWait();
|
|
63266
63342
|
if (this.deferredMessages.length > 0) {
|
|
63267
63343
|
this.input.writeOutput?.(
|
|
63268
63344
|
`agent_bridge_claude_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
|
|
@@ -63353,19 +63429,21 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63353
63429
|
void (async () => {
|
|
63354
63430
|
try {
|
|
63355
63431
|
for await (const message of query) {
|
|
63432
|
+
const interruptSettling = this.interruptSettling;
|
|
63356
63433
|
this.trackToolUseLifecycle(message);
|
|
63357
|
-
let meta3;
|
|
63434
|
+
let meta3 = { interruptSettling };
|
|
63358
63435
|
if (isClaudeAgentTurnResult(message)) {
|
|
63359
63436
|
this.activeTurnCount = Math.max(0, this.activeTurnCount - 1);
|
|
63360
63437
|
meta3 = {
|
|
63438
|
+
interruptSettling,
|
|
63361
63439
|
consumedCommandIds: this.openTurnCommandIds.shift() ?? []
|
|
63362
63440
|
};
|
|
63363
|
-
this.
|
|
63441
|
+
this.pendingToolUses.clear();
|
|
63442
|
+
this.interruptSettling = false;
|
|
63364
63443
|
this.turnResultCount += 1;
|
|
63365
|
-
this.resolveTurnSettlement(true);
|
|
63366
63444
|
this.input.runtimeLogger?.info("agent_bridge_claude_turn_result", {
|
|
63367
63445
|
active_turn_count: this.activeTurnCount,
|
|
63368
|
-
pending_tool_use_count: this.
|
|
63446
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63369
63447
|
turn_result_count: this.turnResultCount,
|
|
63370
63448
|
deferred_count: this.deferredMessages.length,
|
|
63371
63449
|
consumed_command_ids: meta3.consumedCommandIds
|
|
@@ -63373,6 +63451,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63373
63451
|
if (this.activeTurnCount === 0) {
|
|
63374
63452
|
this.flushDeferredMessages();
|
|
63375
63453
|
}
|
|
63454
|
+
if (this.deferredMessages.length === 0) {
|
|
63455
|
+
this.cancelledToolRuns = [];
|
|
63456
|
+
}
|
|
63376
63457
|
}
|
|
63377
63458
|
const failure = probeClaudeAgentMessage(
|
|
63378
63459
|
message,
|
|
@@ -63397,8 +63478,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63397
63478
|
} finally {
|
|
63398
63479
|
this.activeTurnCount = 0;
|
|
63399
63480
|
this.openTurnCommandIds.length = 0;
|
|
63400
|
-
this.
|
|
63401
|
-
this.
|
|
63481
|
+
this.pendingToolUses.clear();
|
|
63482
|
+
this.interruptSettling = false;
|
|
63483
|
+
this.disarmToolBoundaryWait();
|
|
63402
63484
|
this.state = { kind: "closed" };
|
|
63403
63485
|
this.reportExit();
|
|
63404
63486
|
}
|
|
@@ -63415,7 +63497,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63415
63497
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_enqueued", {
|
|
63416
63498
|
state: this.state.kind,
|
|
63417
63499
|
active_turn_count: this.activeTurnCount,
|
|
63418
|
-
pending_tool_use_count: this.
|
|
63500
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
63419
63501
|
deferred_count: this.deferredMessages.length
|
|
63420
63502
|
});
|
|
63421
63503
|
void this.ensureRunningQuery().catch((error51) => {
|
|
@@ -63428,75 +63510,105 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63428
63510
|
return this.activeTurnCount > 0 && this.state.kind === "running";
|
|
63429
63511
|
}
|
|
63430
63512
|
// True while the assistant has an emitted tool_use with no matching
|
|
63431
|
-
// tool_result yet — the window where an immediate interrupt would
|
|
63513
|
+
// tool_result yet — the window where an immediate interrupt would cancel
|
|
63514
|
+
// real tool work, and where an immediate injection would strand an
|
|
63432
63515
|
// unresolved stop_reason=tool_use ahead of the injected user message.
|
|
63433
63516
|
hasInFlightToolUse() {
|
|
63434
|
-
return this.
|
|
63517
|
+
return this.pendingToolUses.size > 0;
|
|
63435
63518
|
}
|
|
63436
63519
|
// Track tool_use/tool_result pairs as they stream so hasInFlightToolUse()
|
|
63437
63520
|
// reflects the live transcript. A tool_use may appear first as a streaming
|
|
63438
63521
|
// content block before the full assistant message is available; the matching
|
|
63439
63522
|
// tool_result closes it; the turn's terminal result clears any remainder.
|
|
63523
|
+
// Two side jobs ride on the same observation point:
|
|
63524
|
+
// - a denial-worded error tool_result arriving while a bridge interrupt is
|
|
63525
|
+
// settling is that interrupt's cancellation of the tool — record it so the
|
|
63526
|
+
// flushed message can tell the model to re-run the cancelled work;
|
|
63527
|
+
// - a tool_result that drains the pending set is the tool boundary an armed
|
|
63528
|
+
// steering message has been waiting for — interrupt the turn now, while no
|
|
63529
|
+
// tool work is at risk.
|
|
63440
63530
|
trackToolUseLifecycle(message) {
|
|
63441
|
-
for (const
|
|
63442
|
-
this.
|
|
63531
|
+
for (const entry of toolUseEntries(message)) {
|
|
63532
|
+
this.pendingToolUses.set(entry.id, {
|
|
63533
|
+
name: entry.name,
|
|
63534
|
+
detail: entry.detail
|
|
63535
|
+
});
|
|
63536
|
+
}
|
|
63537
|
+
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
63538
|
+
for (const result of toolResultEntries(message)) {
|
|
63539
|
+
const pending = this.pendingToolUses.get(result.id);
|
|
63540
|
+
this.pendingToolUses.delete(result.id);
|
|
63541
|
+
if (pending && this.interruptSettling && result.isError && result.text !== null && isClaudeCodePermissionDenialText(result.text)) {
|
|
63542
|
+
this.cancelledToolRuns.push(pending);
|
|
63543
|
+
this.input.writeOutput?.(
|
|
63544
|
+
`agent_bridge_claude_tool_cancellation_observed tool=${pending.name}`
|
|
63545
|
+
);
|
|
63546
|
+
}
|
|
63443
63547
|
}
|
|
63444
|
-
|
|
63445
|
-
this.
|
|
63548
|
+
if (hadInFlightToolUse && !this.hasInFlightToolUse()) {
|
|
63549
|
+
this.fireToolBoundaryInterrupt();
|
|
63446
63550
|
}
|
|
63447
63551
|
}
|
|
63448
|
-
//
|
|
63449
|
-
//
|
|
63450
|
-
//
|
|
63451
|
-
//
|
|
63452
|
-
//
|
|
63453
|
-
|
|
63454
|
-
if (this.
|
|
63455
|
-
return
|
|
63552
|
+
// The pending tool_use set just drained mid-turn. If a steering message is
|
|
63553
|
+
// waiting on that boundary, interrupt the turn now: nothing is executing, so
|
|
63554
|
+
// the cancellation costs only the model's remaining reasoning, and the
|
|
63555
|
+
// turn's terminal result flushes the message. Fire-and-forget — the flush at
|
|
63556
|
+
// the turn result owns delivery whether or not this interrupt lands.
|
|
63557
|
+
fireToolBoundaryInterrupt() {
|
|
63558
|
+
if (!this.toolBoundaryWait || this.deferredMessages.length === 0 || !this.hasInterruptibleTurn()) {
|
|
63559
|
+
return;
|
|
63456
63560
|
}
|
|
63457
|
-
|
|
63458
|
-
|
|
63459
|
-
|
|
63460
|
-
|
|
63461
|
-
|
|
63462
|
-
|
|
63463
|
-
|
|
63464
|
-
|
|
63465
|
-
|
|
63466
|
-
|
|
63467
|
-
|
|
63468
|
-
|
|
63469
|
-
|
|
63470
|
-
|
|
63471
|
-
|
|
63472
|
-
|
|
63473
|
-
|
|
63474
|
-
|
|
63561
|
+
this.disarmToolBoundaryWait();
|
|
63562
|
+
this.input.writeOutput?.(
|
|
63563
|
+
`agent_bridge_claude_tool_boundary_interrupt deferred_count=${this.deferredMessages.length}`
|
|
63564
|
+
);
|
|
63565
|
+
void this.interruptActiveTurn();
|
|
63566
|
+
}
|
|
63567
|
+
// Bound the tool-boundary wait: past the budget the steering message is
|
|
63568
|
+
// judged more urgent than the in-flight tool, which is cancelled mid-run.
|
|
63569
|
+
// The cancellation is observed by trackToolUseLifecycle and reported to the
|
|
63570
|
+
// model in the flushed message's platform notice.
|
|
63571
|
+
armToolBoundaryWait() {
|
|
63572
|
+
if (this.toolBoundaryWait) {
|
|
63573
|
+
return;
|
|
63574
|
+
}
|
|
63575
|
+
const timer = setTimeout(() => {
|
|
63576
|
+
this.toolBoundaryWait = null;
|
|
63577
|
+
if (!this.hasInterruptibleTurn() || this.deferredMessages.length === 0) {
|
|
63578
|
+
return;
|
|
63579
|
+
}
|
|
63580
|
+
this.input.writeOutput?.(
|
|
63581
|
+
`agent_bridge_claude_tool_boundary_wait_timeout pending_tools=${[
|
|
63582
|
+
...this.pendingToolUses.values()
|
|
63583
|
+
].map((tool) => tool.name).join(",")} deferred_count=${this.deferredMessages.length}`
|
|
63475
63584
|
);
|
|
63476
|
-
|
|
63477
|
-
|
|
63478
|
-
|
|
63585
|
+
void this.interruptActiveTurn();
|
|
63586
|
+
}, CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS);
|
|
63587
|
+
timer.unref?.();
|
|
63588
|
+
this.toolBoundaryWait = { timer };
|
|
63479
63589
|
}
|
|
63480
|
-
|
|
63481
|
-
if (this.
|
|
63590
|
+
disarmToolBoundaryWait() {
|
|
63591
|
+
if (!this.toolBoundaryWait) {
|
|
63482
63592
|
return;
|
|
63483
63593
|
}
|
|
63484
|
-
|
|
63485
|
-
this.
|
|
63486
|
-
for (const waiter of waiters) {
|
|
63487
|
-
waiter(settled);
|
|
63488
|
-
}
|
|
63594
|
+
clearTimeout(this.toolBoundaryWait.timer);
|
|
63595
|
+
this.toolBoundaryWait = null;
|
|
63489
63596
|
}
|
|
63490
63597
|
flushDeferredMessages() {
|
|
63491
63598
|
if (this.deferredMessages.length === 0) {
|
|
63492
63599
|
return;
|
|
63493
63600
|
}
|
|
63494
63601
|
const pending = this.deferredMessages.splice(0);
|
|
63602
|
+
const cancelledToolRuns = this.cancelledToolRuns.splice(0);
|
|
63603
|
+
this.disarmToolBoundaryWait();
|
|
63495
63604
|
this.input.writeOutput?.(
|
|
63496
|
-
`agent_bridge_claude_deferred_flush count=${pending.length}`
|
|
63605
|
+
`agent_bridge_claude_deferred_flush count=${pending.length} cancelled_tool_count=${cancelledToolRuns.length}`
|
|
63497
63606
|
);
|
|
63607
|
+
const text = pending.map((entry) => entry.text).join("\n\n");
|
|
63498
63608
|
this.enqueueUserMessage(
|
|
63499
|
-
|
|
63609
|
+
cancelledToolRuns.length > 0 ? `${text}
|
|
63610
|
+
|
|
63611
|
+
${cancelledToolPlatformNotice(cancelledToolRuns)}` : text,
|
|
63500
63612
|
pending.flatMap((entry) => entry.commandIds)
|
|
63501
63613
|
);
|
|
63502
63614
|
}
|
|
@@ -63517,11 +63629,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63517
63629
|
return "proceed";
|
|
63518
63630
|
}
|
|
63519
63631
|
const query = this.state.query;
|
|
63520
|
-
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
63521
63632
|
const settlementBaseline = this.turnResultCount;
|
|
63522
63633
|
const startedAt = Date.now();
|
|
63523
63634
|
this.input.writeOutput?.(
|
|
63524
|
-
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${
|
|
63635
|
+
`agent_bridge_claude_mid_turn_interrupt_started at=${new Date(startedAt).toISOString()} in_flight_tool_use=${this.hasInFlightToolUse()}`
|
|
63525
63636
|
);
|
|
63526
63637
|
const interruptPromise = (async () => {
|
|
63527
63638
|
const ack = await this.requestInterruptAck(query, startedAt);
|
|
@@ -63529,16 +63640,6 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63529
63640
|
this.interruptTimeoutTurn = settlementBaseline;
|
|
63530
63641
|
return "defer";
|
|
63531
63642
|
}
|
|
63532
|
-
if (hadInFlightToolUse) {
|
|
63533
|
-
const settle = await this.awaitTurnSettlement(
|
|
63534
|
-
settlementBaseline,
|
|
63535
|
-
startedAt
|
|
63536
|
-
);
|
|
63537
|
-
if (settle === "timeout") {
|
|
63538
|
-
this.interruptTimeoutTurn = settlementBaseline;
|
|
63539
|
-
return "defer";
|
|
63540
|
-
}
|
|
63541
|
-
}
|
|
63542
63643
|
return "proceed";
|
|
63543
63644
|
})();
|
|
63544
63645
|
this.interruptInFlight = interruptPromise;
|
|
@@ -63575,6 +63676,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
63575
63676
|
);
|
|
63576
63677
|
}, CLAUDE_INTERRUPT_ACK_TIMEOUT_MS);
|
|
63577
63678
|
timer.unref?.();
|
|
63679
|
+
this.interruptSettling = true;
|
|
63578
63680
|
query.interrupt().then(
|
|
63579
63681
|
() => {
|
|
63580
63682
|
if (done) {
|
|
@@ -63931,10 +64033,10 @@ function claudeAgentUserMessage(message) {
|
|
|
63931
64033
|
function isClaudeAgentTurnResult(message) {
|
|
63932
64034
|
return message.type === "result";
|
|
63933
64035
|
}
|
|
63934
|
-
function
|
|
64036
|
+
function toolUseEntries(message) {
|
|
63935
64037
|
if (message.type === "assistant") {
|
|
63936
64038
|
return contentBlocks2(message.message.content).flatMap(
|
|
63937
|
-
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [block2
|
|
64039
|
+
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [toolUseEntryFromBlock(block2)] : []
|
|
63938
64040
|
);
|
|
63939
64041
|
}
|
|
63940
64042
|
if (message.type !== "stream_event") {
|
|
@@ -63945,16 +64047,54 @@ function toolUseIds(message) {
|
|
|
63945
64047
|
return [];
|
|
63946
64048
|
}
|
|
63947
64049
|
const block = event.content_block;
|
|
63948
|
-
return block.type === "tool_use" && typeof block.id === "string" ? [block
|
|
64050
|
+
return block.type === "tool_use" && typeof block.id === "string" ? [toolUseEntryFromBlock(block)] : [];
|
|
63949
64051
|
}
|
|
63950
|
-
function
|
|
64052
|
+
function toolUseEntryFromBlock(block) {
|
|
64053
|
+
return {
|
|
64054
|
+
id: String(block.id),
|
|
64055
|
+
name: typeof block.name === "string" ? block.name : "unknown_tool",
|
|
64056
|
+
detail: toolUseDetail(block.input)
|
|
64057
|
+
};
|
|
64058
|
+
}
|
|
64059
|
+
function toolUseDetail(input) {
|
|
64060
|
+
if (input === void 0 || input === null) {
|
|
64061
|
+
return "";
|
|
64062
|
+
}
|
|
64063
|
+
let text;
|
|
64064
|
+
try {
|
|
64065
|
+
text = JSON.stringify(input);
|
|
64066
|
+
} catch {
|
|
64067
|
+
return "";
|
|
64068
|
+
}
|
|
64069
|
+
if (!text || text === "{}") {
|
|
64070
|
+
return "";
|
|
64071
|
+
}
|
|
64072
|
+
return text.length > 160 ? `${text.slice(0, 160)}\u2026` : text;
|
|
64073
|
+
}
|
|
64074
|
+
function toolResultEntries(message) {
|
|
63951
64075
|
if (message.type !== "user") {
|
|
63952
64076
|
return [];
|
|
63953
64077
|
}
|
|
63954
64078
|
return contentBlocks2(message.message.content).flatMap(
|
|
63955
|
-
(block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [
|
|
64079
|
+
(block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [
|
|
64080
|
+
{
|
|
64081
|
+
id: block.tool_use_id,
|
|
64082
|
+
isError: block.is_error === true,
|
|
64083
|
+
text: typeof block.content === "string" ? block.content : null
|
|
64084
|
+
}
|
|
64085
|
+
] : []
|
|
63956
64086
|
);
|
|
63957
64087
|
}
|
|
64088
|
+
function cancelledToolPlatformNotice(cancelled) {
|
|
64089
|
+
const lines = cancelled.map(
|
|
64090
|
+
(tool) => `- ${tool.name}${tool.detail ? ` ${tool.detail}` : ""}`
|
|
64091
|
+
);
|
|
64092
|
+
return [
|
|
64093
|
+
"[Auto platform notice] To deliver the message above, the platform cancelled the following in-flight tool call(s) mid-execution:",
|
|
64094
|
+
...lines,
|
|
64095
|
+
"This was a platform-initiated cancellation for message delivery, NOT a rejection or permission denial by the user \u2014 ignore any tool result saying the user doesn't want to proceed. Re-run or resume that tool work if it is still needed once you have applied the message."
|
|
64096
|
+
].join("\n");
|
|
64097
|
+
}
|
|
63958
64098
|
function contentBlocks2(content) {
|
|
63959
64099
|
if (!Array.isArray(content)) {
|
|
63960
64100
|
return [];
|
|
@@ -63973,6 +64113,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
63973
64113
|
this.input = input;
|
|
63974
64114
|
this.claudeConfig = input.claude;
|
|
63975
64115
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
64116
|
+
this.projector = new ClaudeCodeProjector({
|
|
64117
|
+
writeOutput: input.writeOutput
|
|
64118
|
+
});
|
|
63976
64119
|
this.readState = input.readState ? new ClaudeReadStateTracker(input.readState) : null;
|
|
63977
64120
|
}
|
|
63978
64121
|
input;
|
|
@@ -63994,7 +64137,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
63994
64137
|
inFlightMessageCommands = /* @__PURE__ */ new Map();
|
|
63995
64138
|
pendingQuestions = /* @__PURE__ */ new Map();
|
|
63996
64139
|
outputBuffer;
|
|
63997
|
-
projector
|
|
64140
|
+
projector;
|
|
63998
64141
|
readState;
|
|
63999
64142
|
livenessTicker = null;
|
|
64000
64143
|
// -----------------------------------------------------------------------------
|
|
@@ -64375,7 +64518,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
64375
64518
|
this.trackReadState(activeContext, message);
|
|
64376
64519
|
let projections;
|
|
64377
64520
|
try {
|
|
64378
|
-
projections = this.projector.project(message
|
|
64521
|
+
projections = this.projector.project(message, {
|
|
64522
|
+
bridgeInterruptSettling: meta3?.interruptSettling === true
|
|
64523
|
+
});
|
|
64379
64524
|
} catch (error51) {
|
|
64380
64525
|
this.input.writeOutput?.(
|
|
64381
64526
|
`agent_bridge_claude_parse_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
|