@autohq/cli 0.1.448 → 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 +275 -133
- package/dist/index.js +278 -134
- 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"
|
|
@@ -36480,23 +36480,14 @@ var SafeTelemetryTextSchema = external_exports.string().transform(
|
|
|
36480
36480
|
return codePoint < 32 || codePoint === 127 ? " " : character;
|
|
36481
36481
|
}).join("").replace(/\s+/g, " ").trim().slice(0, 300).trim()
|
|
36482
36482
|
).pipe(external_exports.string().min(1).max(300));
|
|
36483
|
-
var
|
|
36484
|
-
|
|
36485
|
-
|
|
36486
|
-
|
|
36487
|
-
|
|
36488
|
-
|
|
36489
|
-
|
|
36490
|
-
|
|
36491
|
-
user: PlatformUsageUserSchema
|
|
36492
|
-
}),
|
|
36493
|
-
external_exports.object({
|
|
36494
|
-
kind: external_exports.literal("provider"),
|
|
36495
|
-
provider: SafeTelemetryTextSchema,
|
|
36496
|
-
externalId: external_exports.string().trim().min(1).max(200),
|
|
36497
|
-
displayName: SafeTelemetryTextSchema.nullable()
|
|
36498
|
-
})
|
|
36499
|
-
]);
|
|
36483
|
+
var PlatformUsageActorSchema = external_exports.object({
|
|
36484
|
+
displayName: SafeTelemetryTextSchema,
|
|
36485
|
+
source: SafeTelemetryTextSchema.nullable()
|
|
36486
|
+
}).strict();
|
|
36487
|
+
var PlatformUsageAgentSchema = external_exports.object({
|
|
36488
|
+
displayName: SafeTelemetryTextSchema,
|
|
36489
|
+
model: SafeTelemetryTextSchema.nullable()
|
|
36490
|
+
}).strict();
|
|
36500
36491
|
var PlatformUsageScopeSchema = external_exports.object({
|
|
36501
36492
|
environment: SafeTelemetryTextSchema,
|
|
36502
36493
|
organizationId: external_exports.string().trim().min(1).max(200),
|
|
@@ -36504,13 +36495,13 @@ var PlatformUsageScopeSchema = external_exports.object({
|
|
|
36504
36495
|
projectId: external_exports.string().trim().min(1).max(200).nullable(),
|
|
36505
36496
|
projectName: SafeTelemetryTextSchema.nullable()
|
|
36506
36497
|
});
|
|
36507
|
-
var
|
|
36508
|
-
|
|
36498
|
+
var ScopedActorEventSchema = external_exports.object({
|
|
36499
|
+
actor: PlatformUsageActorSchema,
|
|
36509
36500
|
scope: PlatformUsageScopeSchema
|
|
36510
36501
|
});
|
|
36511
36502
|
var PlatformUsageEventSchema = external_exports.discriminatedUnion("kind", [
|
|
36512
|
-
|
|
36513
|
-
|
|
36503
|
+
ScopedActorEventSchema.extend({ kind: external_exports.literal("user.signup") }),
|
|
36504
|
+
ScopedActorEventSchema.extend({
|
|
36514
36505
|
kind: external_exports.literal("onboarding.lifecycle"),
|
|
36515
36506
|
stage: external_exports.enum(["team_selected", "github_connected", "team_applied"]),
|
|
36516
36507
|
team: SafeTelemetryTextSchema,
|
|
@@ -36520,23 +36511,21 @@ var PlatformUsageEventSchema = external_exports.discriminatedUnion("kind", [
|
|
|
36520
36511
|
failureSummary: SafeTelemetryTextSchema.nullable()
|
|
36521
36512
|
}).nullable()
|
|
36522
36513
|
}),
|
|
36523
|
-
|
|
36514
|
+
ScopedActorEventSchema.extend({
|
|
36524
36515
|
kind: external_exports.literal("agent.created"),
|
|
36525
|
-
|
|
36516
|
+
agent: PlatformUsageAgentSchema
|
|
36526
36517
|
}),
|
|
36527
|
-
|
|
36518
|
+
ScopedActorEventSchema.extend({
|
|
36528
36519
|
kind: external_exports.literal("session.started"),
|
|
36529
|
-
|
|
36530
|
-
scope: PlatformUsageScopeSchema,
|
|
36531
|
-
agentName: SafeTelemetryTextSchema,
|
|
36520
|
+
agent: PlatformUsageAgentSchema,
|
|
36532
36521
|
sessionId: external_exports.string().trim().min(1).max(200)
|
|
36533
36522
|
}),
|
|
36534
|
-
|
|
36523
|
+
ScopedActorEventSchema.extend({
|
|
36535
36524
|
kind: external_exports.literal("credits.added"),
|
|
36536
36525
|
amountUsd: external_exports.number().positive().finite(),
|
|
36537
36526
|
source: external_exports.enum(["purchase", "auto_topup", "adjustment"])
|
|
36538
36527
|
}),
|
|
36539
|
-
|
|
36528
|
+
ScopedActorEventSchema.extend({
|
|
36540
36529
|
kind: external_exports.literal("credits.exhausted"),
|
|
36541
36530
|
autoReloadOutcome: external_exports.enum([
|
|
36542
36531
|
"not_enabled",
|
|
@@ -42808,6 +42797,15 @@ triggers:
|
|
|
42808
42797
|
content: "harness: claude-code\nenvironment:\n name: auto-default-runtime\n image:\n kind: preset\n name: node24\nidentity:\n displayName: Default\n username: default\n description: Auto's built-in general-purpose agent.\ntools:\n auto:\n kind: local\n implementation: auto\n"
|
|
42809
42798
|
}
|
|
42810
42799
|
]
|
|
42800
|
+
},
|
|
42801
|
+
{
|
|
42802
|
+
version: "1.1.0",
|
|
42803
|
+
files: [
|
|
42804
|
+
{
|
|
42805
|
+
path: "fragments/default.yaml",
|
|
42806
|
+
content: "# 1.1.0 bakes the built-in catalog avatar (default.png) into Default's identity so\n# every provisioned agent/default shows the house face instead of an initials\n# fallback. Otherwise byte-identical to 1.0.0.\nharness: claude-code\nenvironment:\n name: auto-default-runtime\n image:\n kind: preset\n name: node24\nidentity:\n displayName: Default\n username: default\n avatar:\n asset: .auto/assets/default.png\n sha256: a5dd97676173a83dfc6fb9bdf30e7f50c7392f9e382fca40a23d6ab9285e9bf2\n description: Auto's built-in general-purpose agent.\ntools:\n auto:\n kind: local\n implementation: auto\n"
|
|
42807
|
+
}
|
|
42808
|
+
]
|
|
42811
42809
|
}
|
|
42812
42810
|
],
|
|
42813
42811
|
"@auto/engineering-tier": [
|
|
@@ -71453,6 +71451,10 @@ function jsonRecordString2(value2, key) {
|
|
|
71453
71451
|
|
|
71454
71452
|
// src/commands/agent-bridge/harness/claude-code/projector.ts
|
|
71455
71453
|
var ClaudeCodeProjector = class {
|
|
71454
|
+
constructor(input = {}) {
|
|
71455
|
+
this.input = input;
|
|
71456
|
+
}
|
|
71457
|
+
input;
|
|
71456
71458
|
currentMessageId = null;
|
|
71457
71459
|
// The turn's UI message id. Claude emits a `message_start` per assistant
|
|
71458
71460
|
// message, but a tool-using turn spans several (message A with the tool call,
|
|
@@ -71471,13 +71473,17 @@ var ClaudeCodeProjector = class {
|
|
|
71471
71473
|
// real turn failure (FRA-3548). Cleared on every result and on the next
|
|
71472
71474
|
// message_start so a stale marker can never reclassify a later failure.
|
|
71473
71475
|
interruptMarkerSeen = false;
|
|
71474
|
-
project(message) {
|
|
71476
|
+
project(message, context = {}) {
|
|
71475
71477
|
if (isClaudeCodeInterruptMarker(message)) {
|
|
71476
71478
|
this.interruptMarkerSeen = true;
|
|
71477
71479
|
}
|
|
71478
71480
|
if (message.type === "stream_event") {
|
|
71479
71481
|
return this.projectStreamEvent(message);
|
|
71480
71482
|
}
|
|
71483
|
+
const interruptContext = {
|
|
71484
|
+
marker: this.interruptMarkerSeen,
|
|
71485
|
+
bridge: context.bridgeInterruptSettling === true
|
|
71486
|
+
};
|
|
71481
71487
|
const parsed = parseClaudeCodeStreamRecord(message);
|
|
71482
71488
|
const snapshotMessageId = assistantSnapshotMessageId(message);
|
|
71483
71489
|
const suppressStreamed = snapshotMessageId !== null && this.streamedMessageIds.has(snapshotMessageId);
|
|
@@ -71489,18 +71495,24 @@ var ClaudeCodeProjector = class {
|
|
|
71489
71495
|
return [];
|
|
71490
71496
|
}
|
|
71491
71497
|
return conversationProjectionToUiChunks(entry, {
|
|
71492
|
-
|
|
71498
|
+
interruptContext,
|
|
71499
|
+
emitDiagnostic: this.input.writeOutput
|
|
71493
71500
|
});
|
|
71494
71501
|
});
|
|
71495
71502
|
if (parsed.result) {
|
|
71496
71503
|
outputs.push(...this.endActiveParts(), ...this.finishActiveToolInputs());
|
|
71497
71504
|
this.currentMessageId = null;
|
|
71498
71505
|
this.activeResponseMessageId = null;
|
|
71499
|
-
|
|
71500
|
-
|
|
71501
|
-
|
|
71502
|
-
})
|
|
71506
|
+
const interrupted = this.isInterruptCancellation(
|
|
71507
|
+
parsed.result,
|
|
71508
|
+
interruptContext
|
|
71503
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 }));
|
|
71504
71516
|
this.interruptMarkerSeen = false;
|
|
71505
71517
|
}
|
|
71506
71518
|
return outputs;
|
|
@@ -71510,9 +71522,11 @@ var ClaudeCodeProjector = class {
|
|
|
71510
71522
|
// surfaces as a diagnostic-only `error_during_execution`. Treating that as a
|
|
71511
71523
|
// turn failure fed the FRA-3548 redelivery loop (the bridge redelivered a
|
|
71512
71524
|
// message the SDK was actively answering), so a failed result bracketed by
|
|
71513
|
-
// the SDK's own
|
|
71514
|
-
|
|
71515
|
-
|
|
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);
|
|
71516
71530
|
}
|
|
71517
71531
|
flushPendingAssistantMessages() {
|
|
71518
71532
|
const outputs = [
|
|
@@ -71633,7 +71647,8 @@ var ClaudeCodeProjector = class {
|
|
|
71633
71647
|
const messageChunks = this.assistantSnapshotMessageChunks(projections);
|
|
71634
71648
|
const rest = projections.filter((projection) => !isAssistantMessageOrToolCall(projection)).flatMap(
|
|
71635
71649
|
(projection) => conversationProjectionToUiChunks(projection, {
|
|
71636
|
-
|
|
71650
|
+
interruptContext: { marker: this.interruptMarkerSeen, bridge: false },
|
|
71651
|
+
emitDiagnostic: this.input.writeOutput
|
|
71637
71652
|
})
|
|
71638
71653
|
);
|
|
71639
71654
|
const last = messageChunks.at(-1);
|
|
@@ -71857,7 +71872,7 @@ function textContentFromDelta(delta) {
|
|
|
71857
71872
|
return null;
|
|
71858
71873
|
}
|
|
71859
71874
|
}
|
|
71860
|
-
function conversationProjectionToUiChunks(projection, options
|
|
71875
|
+
function conversationProjectionToUiChunks(projection, options) {
|
|
71861
71876
|
if (projection.role === "assistant" && projection.kind === "message") {
|
|
71862
71877
|
return messageContentChunks(projection);
|
|
71863
71878
|
}
|
|
@@ -71878,15 +71893,12 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
71878
71893
|
})
|
|
71879
71894
|
];
|
|
71880
71895
|
}
|
|
71881
|
-
const remapped = typeof part.output === "string" ? remapClaudeCodeInterruptToolResultErrorText(part.output, {
|
|
71882
|
-
interrupted: options.interrupted
|
|
71883
|
-
}) : null;
|
|
71884
71896
|
return [
|
|
71885
|
-
|
|
71886
|
-
|
|
71887
|
-
|
|
71888
|
-
|
|
71889
|
-
|
|
71897
|
+
toolResultErrorChunk(
|
|
71898
|
+
part.toolUseId ?? UNKNOWN_MESSAGE_ID,
|
|
71899
|
+
part.output,
|
|
71900
|
+
options
|
|
71901
|
+
)
|
|
71890
71902
|
];
|
|
71891
71903
|
});
|
|
71892
71904
|
}
|
|
@@ -71930,6 +71942,32 @@ function conversationProjectionToUiChunks(projection, options = { interrupted: f
|
|
|
71930
71942
|
}
|
|
71931
71943
|
];
|
|
71932
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
|
+
}
|
|
71933
71971
|
function isAssistantMessageOrToolCall(projection) {
|
|
71934
71972
|
return projection.role === "assistant" && (projection.kind === "message" || projection.kind === "tool_call");
|
|
71935
71973
|
}
|
|
@@ -91974,7 +92012,7 @@ function withClaudeStderrDiagnosticsPointer(error51, capturedStderr) {
|
|
|
91974
92012
|
|
|
91975
92013
|
// src/commands/agent-bridge/harness/claude-code/session.ts
|
|
91976
92014
|
var CLAUDE_AGENT_STARTUP_TIMEOUT_MS = 3e4;
|
|
91977
|
-
var
|
|
92015
|
+
var CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS = 12e4;
|
|
91978
92016
|
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
91979
92017
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e4;
|
|
91980
92018
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
@@ -92050,16 +92088,33 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92050
92088
|
// flushed command id.
|
|
92051
92089
|
openTurnCommandIds = [];
|
|
92052
92090
|
// tool_use ids the assistant has emitted whose tool_result has not yet been
|
|
92053
|
-
// observed
|
|
92054
|
-
//
|
|
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
|
|
92055
92095
|
// stop_reason=tool_use — the invalid transcript that trips Claude Code's
|
|
92056
92096
|
// ede_diagnostic and auto-restarts the session (FRA-3049).
|
|
92057
|
-
|
|
92058
|
-
// Incremented on every turn-terminal `result
|
|
92059
|
-
//
|
|
92060
|
-
// 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.
|
|
92061
92100
|
turnResultCount = 0;
|
|
92062
|
-
|
|
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 = [];
|
|
92063
92118
|
// Memoized MCP-registration gate, keyed by the attached query. A runtime
|
|
92064
92119
|
// restart warms a brand-new session + query, so keying off the query object
|
|
92065
92120
|
// (rather than a session-lifetime flag) re-arms the gate on every restart:
|
|
@@ -92118,18 +92173,34 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92118
92173
|
delivery_mode: mode,
|
|
92119
92174
|
state: this.state.kind,
|
|
92120
92175
|
active_turn_count: this.activeTurnCount,
|
|
92121
|
-
pending_tool_use_count: this.
|
|
92176
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92122
92177
|
deferred_count: this.deferredMessages.length
|
|
92123
92178
|
});
|
|
92124
92179
|
if (mode === "deferred" && this.hasInterruptibleTurn()) {
|
|
92125
92180
|
this.deferredMessages.push({ text: message, commandIds });
|
|
92126
92181
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_deferred", {
|
|
92127
92182
|
active_turn_count: this.activeTurnCount,
|
|
92128
|
-
pending_tool_use_count: this.
|
|
92183
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92129
92184
|
deferred_count: this.deferredMessages.length
|
|
92130
92185
|
});
|
|
92131
92186
|
return;
|
|
92132
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
|
+
}
|
|
92133
92204
|
const interruption = await this.interruptActiveTurnBeforeMessage();
|
|
92134
92205
|
if (interruption === "defer" && this.hasInterruptibleTurn()) {
|
|
92135
92206
|
this.deferredMessages.push({ text: message, commandIds });
|
|
@@ -92137,7 +92208,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92137
92208
|
"agent_bridge_claude_message_deferred_after_interrupt_timeout",
|
|
92138
92209
|
{
|
|
92139
92210
|
active_turn_count: this.activeTurnCount,
|
|
92140
|
-
pending_tool_use_count: this.
|
|
92211
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92141
92212
|
deferred_count: this.deferredMessages.length
|
|
92142
92213
|
}
|
|
92143
92214
|
);
|
|
@@ -92150,7 +92221,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92150
92221
|
duration_ms: Date.now() - startedAt,
|
|
92151
92222
|
state: this.state.kind,
|
|
92152
92223
|
active_turn_count: this.activeTurnCount,
|
|
92153
|
-
pending_tool_use_count: this.
|
|
92224
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92154
92225
|
deferred_count: this.deferredMessages.length
|
|
92155
92226
|
});
|
|
92156
92227
|
}
|
|
@@ -92234,8 +92305,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92234
92305
|
}
|
|
92235
92306
|
this.state = { kind: "closed" };
|
|
92236
92307
|
this.activeTurnCount = 0;
|
|
92237
|
-
this.
|
|
92238
|
-
this.
|
|
92308
|
+
this.pendingToolUses.clear();
|
|
92309
|
+
this.cancelledToolRuns = [];
|
|
92310
|
+
this.interruptSettling = false;
|
|
92311
|
+
this.disarmToolBoundaryWait();
|
|
92239
92312
|
if (this.deferredMessages.length > 0) {
|
|
92240
92313
|
this.input.writeOutput?.(
|
|
92241
92314
|
`agent_bridge_claude_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
|
|
@@ -92326,19 +92399,21 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92326
92399
|
void (async () => {
|
|
92327
92400
|
try {
|
|
92328
92401
|
for await (const message of query) {
|
|
92402
|
+
const interruptSettling = this.interruptSettling;
|
|
92329
92403
|
this.trackToolUseLifecycle(message);
|
|
92330
|
-
let meta3;
|
|
92404
|
+
let meta3 = { interruptSettling };
|
|
92331
92405
|
if (isClaudeAgentTurnResult(message)) {
|
|
92332
92406
|
this.activeTurnCount = Math.max(0, this.activeTurnCount - 1);
|
|
92333
92407
|
meta3 = {
|
|
92408
|
+
interruptSettling,
|
|
92334
92409
|
consumedCommandIds: this.openTurnCommandIds.shift() ?? []
|
|
92335
92410
|
};
|
|
92336
|
-
this.
|
|
92411
|
+
this.pendingToolUses.clear();
|
|
92412
|
+
this.interruptSettling = false;
|
|
92337
92413
|
this.turnResultCount += 1;
|
|
92338
|
-
this.resolveTurnSettlement(true);
|
|
92339
92414
|
this.input.runtimeLogger?.info("agent_bridge_claude_turn_result", {
|
|
92340
92415
|
active_turn_count: this.activeTurnCount,
|
|
92341
|
-
pending_tool_use_count: this.
|
|
92416
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92342
92417
|
turn_result_count: this.turnResultCount,
|
|
92343
92418
|
deferred_count: this.deferredMessages.length,
|
|
92344
92419
|
consumed_command_ids: meta3.consumedCommandIds
|
|
@@ -92346,6 +92421,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92346
92421
|
if (this.activeTurnCount === 0) {
|
|
92347
92422
|
this.flushDeferredMessages();
|
|
92348
92423
|
}
|
|
92424
|
+
if (this.deferredMessages.length === 0) {
|
|
92425
|
+
this.cancelledToolRuns = [];
|
|
92426
|
+
}
|
|
92349
92427
|
}
|
|
92350
92428
|
const failure = probeClaudeAgentMessage(
|
|
92351
92429
|
message,
|
|
@@ -92370,8 +92448,9 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92370
92448
|
} finally {
|
|
92371
92449
|
this.activeTurnCount = 0;
|
|
92372
92450
|
this.openTurnCommandIds.length = 0;
|
|
92373
|
-
this.
|
|
92374
|
-
this.
|
|
92451
|
+
this.pendingToolUses.clear();
|
|
92452
|
+
this.interruptSettling = false;
|
|
92453
|
+
this.disarmToolBoundaryWait();
|
|
92375
92454
|
this.state = { kind: "closed" };
|
|
92376
92455
|
this.reportExit();
|
|
92377
92456
|
}
|
|
@@ -92388,7 +92467,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92388
92467
|
this.input.runtimeLogger?.info("agent_bridge_claude_message_enqueued", {
|
|
92389
92468
|
state: this.state.kind,
|
|
92390
92469
|
active_turn_count: this.activeTurnCount,
|
|
92391
|
-
pending_tool_use_count: this.
|
|
92470
|
+
pending_tool_use_count: this.pendingToolUses.size,
|
|
92392
92471
|
deferred_count: this.deferredMessages.length
|
|
92393
92472
|
});
|
|
92394
92473
|
void this.ensureRunningQuery().catch((error51) => {
|
|
@@ -92401,75 +92480,105 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92401
92480
|
return this.activeTurnCount > 0 && this.state.kind === "running";
|
|
92402
92481
|
}
|
|
92403
92482
|
// True while the assistant has an emitted tool_use with no matching
|
|
92404
|
-
// 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
|
|
92405
92485
|
// unresolved stop_reason=tool_use ahead of the injected user message.
|
|
92406
92486
|
hasInFlightToolUse() {
|
|
92407
|
-
return this.
|
|
92487
|
+
return this.pendingToolUses.size > 0;
|
|
92408
92488
|
}
|
|
92409
92489
|
// Track tool_use/tool_result pairs as they stream so hasInFlightToolUse()
|
|
92410
92490
|
// reflects the live transcript. A tool_use may appear first as a streaming
|
|
92411
92491
|
// content block before the full assistant message is available; the matching
|
|
92412
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.
|
|
92413
92500
|
trackToolUseLifecycle(message) {
|
|
92414
|
-
for (const
|
|
92415
|
-
this.
|
|
92501
|
+
for (const entry of toolUseEntries(message)) {
|
|
92502
|
+
this.pendingToolUses.set(entry.id, {
|
|
92503
|
+
name: entry.name,
|
|
92504
|
+
detail: entry.detail
|
|
92505
|
+
});
|
|
92416
92506
|
}
|
|
92417
|
-
|
|
92418
|
-
|
|
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();
|
|
92419
92520
|
}
|
|
92420
92521
|
}
|
|
92421
|
-
//
|
|
92422
|
-
//
|
|
92423
|
-
//
|
|
92424
|
-
//
|
|
92425
|
-
//
|
|
92426
|
-
|
|
92427
|
-
if (this.
|
|
92428
|
-
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;
|
|
92429
92530
|
}
|
|
92430
|
-
|
|
92431
|
-
|
|
92432
|
-
|
|
92433
|
-
|
|
92434
|
-
|
|
92435
|
-
|
|
92436
|
-
|
|
92437
|
-
|
|
92438
|
-
|
|
92439
|
-
|
|
92440
|
-
|
|
92441
|
-
|
|
92442
|
-
|
|
92443
|
-
|
|
92444
|
-
|
|
92445
|
-
|
|
92446
|
-
|
|
92447
|
-
|
|
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}`
|
|
92448
92554
|
);
|
|
92449
|
-
|
|
92450
|
-
|
|
92451
|
-
|
|
92555
|
+
void this.interruptActiveTurn();
|
|
92556
|
+
}, CLAUDE_TOOL_BOUNDARY_WAIT_TIMEOUT_MS);
|
|
92557
|
+
timer.unref?.();
|
|
92558
|
+
this.toolBoundaryWait = { timer };
|
|
92452
92559
|
}
|
|
92453
|
-
|
|
92454
|
-
if (this.
|
|
92560
|
+
disarmToolBoundaryWait() {
|
|
92561
|
+
if (!this.toolBoundaryWait) {
|
|
92455
92562
|
return;
|
|
92456
92563
|
}
|
|
92457
|
-
|
|
92458
|
-
this.
|
|
92459
|
-
for (const waiter of waiters) {
|
|
92460
|
-
waiter(settled);
|
|
92461
|
-
}
|
|
92564
|
+
clearTimeout(this.toolBoundaryWait.timer);
|
|
92565
|
+
this.toolBoundaryWait = null;
|
|
92462
92566
|
}
|
|
92463
92567
|
flushDeferredMessages() {
|
|
92464
92568
|
if (this.deferredMessages.length === 0) {
|
|
92465
92569
|
return;
|
|
92466
92570
|
}
|
|
92467
92571
|
const pending = this.deferredMessages.splice(0);
|
|
92572
|
+
const cancelledToolRuns = this.cancelledToolRuns.splice(0);
|
|
92573
|
+
this.disarmToolBoundaryWait();
|
|
92468
92574
|
this.input.writeOutput?.(
|
|
92469
|
-
`agent_bridge_claude_deferred_flush count=${pending.length}`
|
|
92575
|
+
`agent_bridge_claude_deferred_flush count=${pending.length} cancelled_tool_count=${cancelledToolRuns.length}`
|
|
92470
92576
|
);
|
|
92577
|
+
const text2 = pending.map((entry) => entry.text).join("\n\n");
|
|
92471
92578
|
this.enqueueUserMessage(
|
|
92472
|
-
|
|
92579
|
+
cancelledToolRuns.length > 0 ? `${text2}
|
|
92580
|
+
|
|
92581
|
+
${cancelledToolPlatformNotice(cancelledToolRuns)}` : text2,
|
|
92473
92582
|
pending.flatMap((entry) => entry.commandIds)
|
|
92474
92583
|
);
|
|
92475
92584
|
}
|
|
@@ -92490,11 +92599,10 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92490
92599
|
return "proceed";
|
|
92491
92600
|
}
|
|
92492
92601
|
const query = this.state.query;
|
|
92493
|
-
const hadInFlightToolUse = this.hasInFlightToolUse();
|
|
92494
92602
|
const settlementBaseline = this.turnResultCount;
|
|
92495
92603
|
const startedAt = Date.now();
|
|
92496
92604
|
this.input.writeOutput?.(
|
|
92497
|
-
`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()}`
|
|
92498
92606
|
);
|
|
92499
92607
|
const interruptPromise = (async () => {
|
|
92500
92608
|
const ack = await this.requestInterruptAck(query, startedAt);
|
|
@@ -92502,16 +92610,6 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92502
92610
|
this.interruptTimeoutTurn = settlementBaseline;
|
|
92503
92611
|
return "defer";
|
|
92504
92612
|
}
|
|
92505
|
-
if (hadInFlightToolUse) {
|
|
92506
|
-
const settle = await this.awaitTurnSettlement(
|
|
92507
|
-
settlementBaseline,
|
|
92508
|
-
startedAt
|
|
92509
|
-
);
|
|
92510
|
-
if (settle === "timeout") {
|
|
92511
|
-
this.interruptTimeoutTurn = settlementBaseline;
|
|
92512
|
-
return "defer";
|
|
92513
|
-
}
|
|
92514
|
-
}
|
|
92515
92613
|
return "proceed";
|
|
92516
92614
|
})();
|
|
92517
92615
|
this.interruptInFlight = interruptPromise;
|
|
@@ -92548,6 +92646,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
92548
92646
|
);
|
|
92549
92647
|
}, CLAUDE_INTERRUPT_ACK_TIMEOUT_MS);
|
|
92550
92648
|
timer.unref?.();
|
|
92649
|
+
this.interruptSettling = true;
|
|
92551
92650
|
query.interrupt().then(
|
|
92552
92651
|
() => {
|
|
92553
92652
|
if (done) {
|
|
@@ -92904,10 +93003,10 @@ function claudeAgentUserMessage(message) {
|
|
|
92904
93003
|
function isClaudeAgentTurnResult(message) {
|
|
92905
93004
|
return message.type === "result";
|
|
92906
93005
|
}
|
|
92907
|
-
function
|
|
93006
|
+
function toolUseEntries(message) {
|
|
92908
93007
|
if (message.type === "assistant") {
|
|
92909
93008
|
return contentBlocks2(message.message.content).flatMap(
|
|
92910
|
-
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [block2
|
|
93009
|
+
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [toolUseEntryFromBlock(block2)] : []
|
|
92911
93010
|
);
|
|
92912
93011
|
}
|
|
92913
93012
|
if (message.type !== "stream_event") {
|
|
@@ -92918,16 +93017,54 @@ function toolUseIds(message) {
|
|
|
92918
93017
|
return [];
|
|
92919
93018
|
}
|
|
92920
93019
|
const block = event.content_block;
|
|
92921
|
-
return block.type === "tool_use" && typeof block.id === "string" ? [block
|
|
93020
|
+
return block.type === "tool_use" && typeof block.id === "string" ? [toolUseEntryFromBlock(block)] : [];
|
|
93021
|
+
}
|
|
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;
|
|
92922
93043
|
}
|
|
92923
|
-
function
|
|
93044
|
+
function toolResultEntries(message) {
|
|
92924
93045
|
if (message.type !== "user") {
|
|
92925
93046
|
return [];
|
|
92926
93047
|
}
|
|
92927
93048
|
return contentBlocks2(message.message.content).flatMap(
|
|
92928
|
-
(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
|
+
] : []
|
|
92929
93056
|
);
|
|
92930
93057
|
}
|
|
93058
|
+
function cancelledToolPlatformNotice(cancelled) {
|
|
93059
|
+
const lines = cancelled.map(
|
|
93060
|
+
(tool) => `- ${tool.name}${tool.detail ? ` ${tool.detail}` : ""}`
|
|
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");
|
|
93067
|
+
}
|
|
92931
93068
|
function contentBlocks2(content) {
|
|
92932
93069
|
if (!Array.isArray(content)) {
|
|
92933
93070
|
return [];
|
|
@@ -92946,6 +93083,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
92946
93083
|
this.input = input;
|
|
92947
93084
|
this.claudeConfig = input.claude;
|
|
92948
93085
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
93086
|
+
this.projector = new ClaudeCodeProjector({
|
|
93087
|
+
writeOutput: input.writeOutput
|
|
93088
|
+
});
|
|
92949
93089
|
this.readState = input.readState ? new ClaudeReadStateTracker(input.readState) : null;
|
|
92950
93090
|
}
|
|
92951
93091
|
input;
|
|
@@ -92967,7 +93107,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
92967
93107
|
inFlightMessageCommands = /* @__PURE__ */ new Map();
|
|
92968
93108
|
pendingQuestions = /* @__PURE__ */ new Map();
|
|
92969
93109
|
outputBuffer;
|
|
92970
|
-
projector
|
|
93110
|
+
projector;
|
|
92971
93111
|
readState;
|
|
92972
93112
|
livenessTicker = null;
|
|
92973
93113
|
// -----------------------------------------------------------------------------
|
|
@@ -93348,7 +93488,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
93348
93488
|
this.trackReadState(activeContext, message);
|
|
93349
93489
|
let projections;
|
|
93350
93490
|
try {
|
|
93351
|
-
projections = this.projector.project(message
|
|
93491
|
+
projections = this.projector.project(message, {
|
|
93492
|
+
bridgeInterruptSettling: meta3?.interruptSettling === true
|
|
93493
|
+
});
|
|
93352
93494
|
} catch (error51) {
|
|
93353
93495
|
this.input.writeOutput?.(
|
|
93354
93496
|
`agent_bridge_claude_parse_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
|