@vanillagreen/pi-claude-bridge 4.0.1 → 4.0.2
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/README.md +5 -1
- package/bundle/connector-inventory.js +8 -7
- package/bundle/index.js +254 -74
- package/package.json +3 -2
- package/src/assistant-stream.ts +4 -3
- package/src/billing-identity.ts +116 -0
- package/src/bridge-state.ts +9 -6
- package/src/connector-audit.ts +9 -5
- package/src/connector-inventory.ts +8 -8
- package/src/connectors.ts +1 -0
- package/src/consume-query.ts +17 -2
- package/src/index.ts +210 -42
- package/src/native-provider.ts +3 -1
- package/src/query-state.ts +65 -11
- package/src/query-teardown.ts +16 -0
- package/src/session-persistence.ts +5 -5
- package/src/session-verify.ts +5 -5
- package/src/tool-pairing-audit.ts +2 -1
package/bundle/index.js
CHANGED
|
@@ -36017,7 +36017,8 @@ async function listAccountConnectors(deps) {
|
|
|
36017
36017
|
const { credentials, apiBase, signal } = deps;
|
|
36018
36018
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
36019
36019
|
const url2 = connectorsListUrl(credentials.organizationUuid, apiBase);
|
|
36020
|
-
const fail = (reason) => ({ ok: false, complete: false, reason: redactSecret(
|
|
36020
|
+
const fail = (key, value, reason) => ({ ok: false, complete: false, reason: redactSecret(`${key}=${JSON.stringify(value)}
|
|
36021
|
+
${reason}`, credentials.accessToken) });
|
|
36021
36022
|
let response;
|
|
36022
36023
|
try {
|
|
36023
36024
|
response = await fetchImpl(url2, {
|
|
@@ -36031,32 +36032,32 @@ async function listAccountConnectors(deps) {
|
|
|
36031
36032
|
signal
|
|
36032
36033
|
});
|
|
36033
36034
|
} catch (error51) {
|
|
36034
|
-
return fail(`connector list request failed: ${errorText(error51)}`);
|
|
36035
|
+
return fail("connector-request", "transport", `connector list request failed: ${errorText(error51)}`);
|
|
36035
36036
|
}
|
|
36036
36037
|
let bodyText;
|
|
36037
36038
|
try {
|
|
36038
36039
|
bodyText = await response.text();
|
|
36039
36040
|
} catch (error51) {
|
|
36040
|
-
return fail(`connector list response unreadable: ${errorText(error51)}`);
|
|
36041
|
+
return fail("connector-response", "unreadable", `connector list response unreadable: ${errorText(error51)}`);
|
|
36041
36042
|
}
|
|
36042
36043
|
if (!response.ok) {
|
|
36043
|
-
return fail(`connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
|
|
36044
|
+
return fail("connector-http", response.status, `connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
|
|
36044
36045
|
}
|
|
36045
36046
|
let parsed;
|
|
36046
36047
|
try {
|
|
36047
36048
|
parsed = JSON.parse(bodyText);
|
|
36048
36049
|
} catch {
|
|
36049
|
-
return fail("connector list returned a non-JSON body");
|
|
36050
|
+
return fail("connector-json", "invalid", "connector list returned a non-JSON body");
|
|
36050
36051
|
}
|
|
36051
36052
|
if (!Array.isArray(parsed?.results)) {
|
|
36052
|
-
return fail("connector list response had no results array");
|
|
36053
|
+
return fail("connector-results", "not-array", "connector list response had no results array");
|
|
36053
36054
|
}
|
|
36054
36055
|
const connectors = [];
|
|
36055
36056
|
for (const raw of parsed.results) {
|
|
36056
36057
|
const entry = raw;
|
|
36057
36058
|
const name = nonEmptyString(entry?.name);
|
|
36058
36059
|
if (!name) {
|
|
36059
|
-
return fail("connector list contained an entry with no name");
|
|
36060
|
+
return fail("connector-name", connectors.length, "connector list contained an entry with no name");
|
|
36060
36061
|
}
|
|
36061
36062
|
connectors.push({
|
|
36062
36063
|
name,
|
|
@@ -36369,7 +36370,8 @@ function connectorWriteDenyOutput(toolName) {
|
|
|
36369
36370
|
hookSpecificOutput: {
|
|
36370
36371
|
hookEventName: "PreToolUse",
|
|
36371
36372
|
permissionDecision: "deny",
|
|
36372
|
-
permissionDecisionReason: `
|
|
36373
|
+
permissionDecisionReason: `connector-write-denied=${JSON.stringify(toolName)}
|
|
36374
|
+
Connector write tool "${toolName}" is blocked in read-only connector mode. Connector writes must go through the host application's gated approval flow.`
|
|
36373
36375
|
}
|
|
36374
36376
|
};
|
|
36375
36377
|
}
|
|
@@ -36761,7 +36763,8 @@ var DRAIN_CAUSE_TEXT = {
|
|
|
36761
36763
|
};
|
|
36762
36764
|
function interruptedToolCallResult(cause) {
|
|
36763
36765
|
return {
|
|
36764
|
-
content: [{ type: "text", text: `
|
|
36766
|
+
content: [{ type: "text", text: `tool-call-drain=${cause}
|
|
36767
|
+
Claude bridge: ${DRAIN_CAUSE_TEXT[cause]} before this tool call's result was delivered. The call did not complete and produced no output.` }],
|
|
36765
36768
|
isError: true
|
|
36766
36769
|
};
|
|
36767
36770
|
}
|
|
@@ -36780,7 +36783,7 @@ function drainPendingToolCalls(queryCtx, cause) {
|
|
|
36780
36783
|
}
|
|
36781
36784
|
function strandedToolCallResult() {
|
|
36782
36785
|
return {
|
|
36783
|
-
content: [{ type: "text", text: "
|
|
36786
|
+
content: [{ type: "text", text: "tool-call-stranded=unforwarded\nClaude bridge: this tool call was never forwarded to Pi before its turn ended, so it did not execute and no result can arrive. Re-run the tool." }],
|
|
36784
36787
|
isError: true
|
|
36785
36788
|
};
|
|
36786
36789
|
}
|
|
@@ -36856,6 +36859,22 @@ var QueryContext = class {
|
|
|
36856
36859
|
// Query-scoped (fully isolated per query)
|
|
36857
36860
|
activeQuery = null;
|
|
36858
36861
|
currentPiStream = null;
|
|
36862
|
+
/** Pi replaced the history this query's Claude session was built from
|
|
36863
|
+
* (compaction, history navigation) while the query was still running.
|
|
36864
|
+
* Delivering further tool results into it would keep Claude Code on history
|
|
36865
|
+
* Pi no longer holds, so the next provider callback restarts the query from
|
|
36866
|
+
* Pi's new context. A query that ENDS while this is set persists its record
|
|
36867
|
+
* with needsRebuild, so the next turn rebuilds either way. */
|
|
36868
|
+
piHistoryReplaced = false;
|
|
36869
|
+
/** The handover this replacement asked for was refused, and the refusal is
|
|
36870
|
+
* already reported. Every later callback of the query re-reads
|
|
36871
|
+
* `piHistoryReplaced`, which stays set, so without this the same refusal
|
|
36872
|
+
* would be recorded once per remaining tool result. */
|
|
36873
|
+
reportedHistoryRestartDecline = false;
|
|
36874
|
+
/** The provider callback that observed `piHistoryReplaced`. The dying query's
|
|
36875
|
+
* own promise chain runs it, after teardown released the query state, and
|
|
36876
|
+
* feeds the replacement query's events into that callback's stream. */
|
|
36877
|
+
restartRequest = null;
|
|
36859
36878
|
latestCursor = 0;
|
|
36860
36879
|
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
36861
36880
|
pendingResults = /* @__PURE__ */ new Map();
|
|
@@ -36940,14 +36959,20 @@ var QueryContext = class {
|
|
|
36940
36959
|
/** tool_use id → raw SDK tool name. */
|
|
36941
36960
|
childExecutedToolCalls = /* @__PURE__ */ new Map();
|
|
36942
36961
|
/**
|
|
36943
|
-
*
|
|
36962
|
+
* Every call the CHILD executed that pi's messages cannot carry — a claude.ai
|
|
36963
|
+
* connector, or a foreign MCP tool the child loaded itself — keyed by tool_use
|
|
36964
|
+
* id. Nothing can rebuild these from pi's context, so a history handover is
|
|
36965
|
+
* refused while the map is non-empty. Connector entries also back the
|
|
36966
|
+
* connector-call audit trail (see connector-audit.ts).
|
|
36944
36967
|
*
|
|
36945
36968
|
* Query-scoped and deliberately NOT cleared by resetToolTracking: that runs at
|
|
36946
36969
|
* every child message boundary, and a call issued in one child message is only
|
|
36947
36970
|
* reconciled after that message ends. Clearing it there would make an abandoned
|
|
36948
36971
|
* call unrecordable at teardown — which is the one case the trail exists for.
|
|
36972
|
+
* Fresh-query setup clears it instead, once teardown has flushed it: a reused
|
|
36973
|
+
* top-level context would otherwise answer for calls an earlier query made.
|
|
36949
36974
|
*/
|
|
36950
|
-
|
|
36975
|
+
childSideCalls = /* @__PURE__ */ new Map();
|
|
36951
36976
|
/** Claude Code session id for this query, from the SDK's `system` init message.
|
|
36952
36977
|
* Undefined until it arrives; the audit trail omits the field rather than
|
|
36953
36978
|
* guessing. */
|
|
@@ -37004,7 +37029,7 @@ var QueryContext = class {
|
|
|
37004
37029
|
turnSawStreamEvent = false;
|
|
37005
37030
|
turnSawToolCall = false;
|
|
37006
37031
|
get turnBlocks() {
|
|
37007
|
-
if (!this.turnOutput) throw new Error("turnBlocks accessed before resetTurnState");
|
|
37032
|
+
if (!this.turnOutput) throw new Error("turn-state-uninitialized=turnBlocks\nturnBlocks accessed before resetTurnState");
|
|
37008
37033
|
return this.turnOutput.content;
|
|
37009
37034
|
}
|
|
37010
37035
|
resetTurnState(model) {
|
|
@@ -37061,9 +37086,10 @@ var QueryContext = class {
|
|
|
37061
37086
|
}
|
|
37062
37087
|
if (id2 && isConnectorTool(rawName)) {
|
|
37063
37088
|
this.childExecutedToolCalls.set(id2, rawName);
|
|
37064
|
-
if (!this.
|
|
37065
|
-
this.
|
|
37089
|
+
if (!this.childSideCalls.has(id2)) {
|
|
37090
|
+
this.childSideCalls.set(id2, {
|
|
37066
37091
|
name: rawName,
|
|
37092
|
+
kind: "connector",
|
|
37067
37093
|
...this.childSessionId ? { childSessionId: this.childSessionId } : {},
|
|
37068
37094
|
recorded: false
|
|
37069
37095
|
});
|
|
@@ -37071,6 +37097,20 @@ var QueryContext = class {
|
|
|
37071
37097
|
}
|
|
37072
37098
|
if (typeof streamIndex === "number") this.childExecutedStreamIndexes.add(streamIndex);
|
|
37073
37099
|
}
|
|
37100
|
+
/** A foreign MCP tool the child loaded from filesystem settings and ran
|
|
37101
|
+
* itself. Pi never sees the call or its result, so it commits the turn the
|
|
37102
|
+
* same way a connector does and joins the same map: a rebuild from pi's
|
|
37103
|
+
* context would erase an account-visible operation the model could repeat. */
|
|
37104
|
+
noteForeignMcpToolCall(id2, rawName) {
|
|
37105
|
+
this.markOutputCommitted();
|
|
37106
|
+
if (!id2 || this.childSideCalls.has(id2)) return;
|
|
37107
|
+
this.childSideCalls.set(id2, {
|
|
37108
|
+
name: rawName,
|
|
37109
|
+
kind: "foreign-mcp",
|
|
37110
|
+
...this.childSessionId ? { childSessionId: this.childSessionId } : {},
|
|
37111
|
+
recorded: false
|
|
37112
|
+
});
|
|
37113
|
+
}
|
|
37074
37114
|
recordToolCall(id2, toolName, args = {}) {
|
|
37075
37115
|
if (!id2) return;
|
|
37076
37116
|
this.queryToolNames.set(id2, toolName);
|
|
@@ -37238,13 +37278,13 @@ function stackDepth() {
|
|
|
37238
37278
|
}
|
|
37239
37279
|
function pushContext() {
|
|
37240
37280
|
const state = lane();
|
|
37241
|
-
if (!state.current.activeQuery) throw new Error("
|
|
37281
|
+
if (!state.current.activeQuery) throw new Error("query-stack-push=inactive\npushContext() called with no active query");
|
|
37242
37282
|
state.stack.push(state.current);
|
|
37243
37283
|
state.current = new QueryContext();
|
|
37244
37284
|
}
|
|
37245
37285
|
function popContext() {
|
|
37246
37286
|
const state = lane();
|
|
37247
|
-
if (state.stack.length === 0) throw new Error("
|
|
37287
|
+
if (state.stack.length === 0) throw new Error("query-stack-pop=empty\npopContext() called with empty stack");
|
|
37248
37288
|
const parent = state.stack[state.stack.length - 1];
|
|
37249
37289
|
parent.deferredUserMessages.push(...state.current.deferredUserMessages);
|
|
37250
37290
|
state.current = state.stack.pop();
|
|
@@ -37340,7 +37380,7 @@ function findUnpairedToolUses(messages) {
|
|
|
37340
37380
|
}
|
|
37341
37381
|
return missing;
|
|
37342
37382
|
}
|
|
37343
|
-
var LOST_TOOL_RESULT_TEXT = "
|
|
37383
|
+
var LOST_TOOL_RESULT_TEXT = "tool-result-lost=interrupted\nClaude bridge: the result of this tool call was lost before the session was rebuilt (the turn was interrupted). Treat the call as failed \u2014 it may or may not have executed. Re-run the tool if its output is still needed.";
|
|
37344
37384
|
function insertLostToolResultPlaceholders(messages, missing) {
|
|
37345
37385
|
const block = (id2) => ({ type: "tool_result", tool_use_id: id2, content: LOST_TOOL_RESULT_TEXT, is_error: true });
|
|
37346
37386
|
const byAssistant = /* @__PURE__ */ new Map();
|
|
@@ -37527,7 +37567,8 @@ function reportToolResultMismatch(queryCtx, reason, cwd, opts = {}) {
|
|
|
37527
37567
|
unmatchedResultIds: progress.unmatchedResultIds
|
|
37528
37568
|
});
|
|
37529
37569
|
safeNotify(
|
|
37530
|
-
`
|
|
37570
|
+
`tool-result-mismatch=${JSON.stringify({ delivered: progress.deliveredCount, expected: progress.expectedCount, resolved: progress.resolvedCount, diagnostic: DEBUG ? diagLogPath() : "CLAUDE_BRIDGE_DEBUG=1" })}
|
|
37571
|
+
Claude bridge: tool result delivery interrupted during ${reason}; delivered ${progress.deliveredCount}/${progress.expectedCount}, resolved ${progress.resolvedCount}/${progress.expectedCount}, waiting=${progress.waitingCount}, queued=${progress.queuedCount}, unmatched=${progress.unmatchedResultCount}${toolNameSummary.length ? `, tools=${toolNameSummary.join(", ")}` : ""}. ` + (queryCtx.detachedFromSharedSession ? `Detached one-shot query \u2014 shared Claude session record left untouched; ${diagGuidance()}.` : `Claude session will rebuild before the next turn; ${diagGuidance()}.`),
|
|
37531
37572
|
"error"
|
|
37532
37573
|
);
|
|
37533
37574
|
return true;
|
|
@@ -37587,10 +37628,10 @@ function appendConnectorCallAudit(data) {
|
|
|
37587
37628
|
return delivered;
|
|
37588
37629
|
}
|
|
37589
37630
|
function recordConnectorCallResult(queryCtx, toolUseId, name, isError, byteSize) {
|
|
37590
|
-
const pending = queryCtx.
|
|
37631
|
+
const pending = queryCtx.childSideCalls.get(toolUseId);
|
|
37591
37632
|
if (pending?.recorded) return false;
|
|
37592
37633
|
const childSessionId = pending?.childSessionId ?? queryCtx.childSessionId;
|
|
37593
|
-
queryCtx.
|
|
37634
|
+
queryCtx.childSideCalls.set(toolUseId, { ...pending, kind: pending?.kind ?? "connector", name, childSessionId, recorded: true });
|
|
37594
37635
|
return appendConnectorCallAudit({
|
|
37595
37636
|
name,
|
|
37596
37637
|
toolUseId,
|
|
@@ -37601,9 +37642,9 @@ function recordConnectorCallResult(queryCtx, toolUseId, name, isError, byteSize)
|
|
|
37601
37642
|
}
|
|
37602
37643
|
function flushConnectorCallAudit(queryCtx, reason) {
|
|
37603
37644
|
let appended = 0;
|
|
37604
|
-
for (const [toolUseId, state] of queryCtx.
|
|
37605
|
-
if (state.recorded) continue;
|
|
37606
|
-
queryCtx.
|
|
37645
|
+
for (const [toolUseId, state] of queryCtx.childSideCalls) {
|
|
37646
|
+
if (state.recorded || state.kind !== "connector") continue;
|
|
37647
|
+
queryCtx.childSideCalls.set(toolUseId, { ...state, recorded: true });
|
|
37607
37648
|
const childSessionId = state.childSessionId ?? queryCtx.childSessionId;
|
|
37608
37649
|
if (appendConnectorCallAudit({
|
|
37609
37650
|
name: state.name,
|
|
@@ -37617,6 +37658,18 @@ function flushConnectorCallAudit(queryCtx, reason) {
|
|
|
37617
37658
|
}
|
|
37618
37659
|
|
|
37619
37660
|
// src/query-teardown.ts
|
|
37661
|
+
function closeSdkQuery(sdkQuery) {
|
|
37662
|
+
try {
|
|
37663
|
+
sdkQuery.close();
|
|
37664
|
+
} catch (error51) {
|
|
37665
|
+
debug("provider: closing the sdk query threw; continuing teardown:", error51);
|
|
37666
|
+
}
|
|
37667
|
+
}
|
|
37668
|
+
function abortSdkQuery(sdkQuery) {
|
|
37669
|
+
void sdkQuery.interrupt().catch(() => {
|
|
37670
|
+
});
|
|
37671
|
+
closeSdkQuery(sdkQuery);
|
|
37672
|
+
}
|
|
37620
37673
|
function teardownQuery(queryCtx, sdkQuery, cause, cwd, isReentrant) {
|
|
37621
37674
|
if (queryCtx.activeQuery !== sdkQuery) return false;
|
|
37622
37675
|
reportToolResultMismatch(queryCtx, "query teardown", cwd, { forceRotate: cause !== "query-end" });
|
|
@@ -37687,7 +37740,9 @@ function claudeAuthSourceLabel(env = process.env) {
|
|
|
37687
37740
|
return "Claude Code login";
|
|
37688
37741
|
}
|
|
37689
37742
|
function buildNativeProvider(piAi2, models, streamSimple, env = process.env, hasCredentials = () => hasClaudeCredentials(env)) {
|
|
37690
|
-
if (!supportsNativeProvider(piAi2))
|
|
37743
|
+
if (!supportsNativeProvider(piAi2)) {
|
|
37744
|
+
throw Object.assign(new Error(NATIVE_PROVIDER_UNSUPPORTED_MESSAGE), { code: "CLAUDE_BRIDGE_NATIVE_PROVIDER_UNSUPPORTED" });
|
|
37745
|
+
}
|
|
37691
37746
|
const stamped = models.map((model) => ({ ...model, api: "claude-bridge", baseUrl: "claude-bridge", provider: PROVIDER_ID }));
|
|
37692
37747
|
const streams = {
|
|
37693
37748
|
stream: streamSimple,
|
|
@@ -53144,28 +53199,33 @@ function verifyWrittenSession(jsonlPath, expectedSessionId, expectedRecordCount)
|
|
|
53144
53199
|
try {
|
|
53145
53200
|
st2 = statSync3(jsonlPath);
|
|
53146
53201
|
} catch (e) {
|
|
53147
|
-
warnings.push(`file
|
|
53202
|
+
warnings.push(`session-file-missing=${jsonlPath}
|
|
53203
|
+
File missing after save: ${e.message}`);
|
|
53148
53204
|
return warnings;
|
|
53149
53205
|
}
|
|
53150
53206
|
let summary;
|
|
53151
53207
|
try {
|
|
53152
53208
|
summary = summarizeJsonl(jsonlPath);
|
|
53153
53209
|
} catch (e) {
|
|
53154
|
-
warnings.push(`file
|
|
53210
|
+
warnings.push(`session-file-unreadable=${jsonlPath}
|
|
53211
|
+
File unreadable: size=${st2.size} error=${e.message}`);
|
|
53155
53212
|
return warnings;
|
|
53156
53213
|
}
|
|
53157
53214
|
if (summary.count !== expectedRecordCount) {
|
|
53158
|
-
warnings.push(`record
|
|
53215
|
+
warnings.push(`session-record-count=${summary.count} expected=${expectedRecordCount}
|
|
53216
|
+
Record count differs: path=${jsonlPath} bytes=${st2.size}`);
|
|
53159
53217
|
return warnings;
|
|
53160
53218
|
}
|
|
53161
53219
|
try {
|
|
53162
53220
|
const firstRec = JSON.parse(summary.firstLine ?? "");
|
|
53163
53221
|
const lastRec = JSON.parse(summary.lastLine ?? "");
|
|
53164
53222
|
if (firstRec.sessionId !== expectedSessionId || lastRec.sessionId !== expectedSessionId) {
|
|
53165
|
-
warnings.push(`
|
|
53223
|
+
warnings.push(`session-id-drift=${expectedSessionId} first=${firstRec.sessionId} last=${lastRec.sessionId}
|
|
53224
|
+
Session identity differs from the expected identity.`);
|
|
53166
53225
|
}
|
|
53167
53226
|
} catch (e) {
|
|
53168
|
-
warnings.push(`
|
|
53227
|
+
warnings.push(`session-json-invalid=${jsonlPath}
|
|
53228
|
+
Malformed JSONL: ${e.message}`);
|
|
53169
53229
|
}
|
|
53170
53230
|
return warnings;
|
|
53171
53231
|
}
|
|
@@ -53481,12 +53541,14 @@ function canonicalize(p) {
|
|
|
53481
53541
|
}
|
|
53482
53542
|
}
|
|
53483
53543
|
function shouldRestorePersistedBridgeEntry(persisted, currentPiSessionId, currentCwd) {
|
|
53484
|
-
if (!persisted.piSessionId) return "missing piSessionId";
|
|
53544
|
+
if (!persisted.piSessionId) return "restore-session-missing=piSessionId\nMissing piSessionId.";
|
|
53485
53545
|
if (currentPiSessionId && persisted.piSessionId !== currentPiSessionId) {
|
|
53486
|
-
return `
|
|
53546
|
+
return `restore-session-mismatch=${persisted.piSessionId} current=${currentPiSessionId}
|
|
53547
|
+
The persisted session differs from the active session.`;
|
|
53487
53548
|
}
|
|
53488
53549
|
if (currentCwd && canonicalize(persisted.cwd) !== canonicalize(currentCwd)) {
|
|
53489
|
-
return `cwd
|
|
53550
|
+
return `restore-cwd-mismatch=${persisted.cwd} current=${currentCwd}
|
|
53551
|
+
The persisted working directory differs from the active directory.`;
|
|
53490
53552
|
}
|
|
53491
53553
|
return void 0;
|
|
53492
53554
|
}
|
|
@@ -53640,7 +53702,7 @@ function verifyWrittenSession2(jsonlPath, expectedSessionId, expectedRecordCount
|
|
|
53640
53702
|
for (const msg of warnings) {
|
|
53641
53703
|
debug(`WARNING session verify: ${msg}`);
|
|
53642
53704
|
safeNotify(
|
|
53643
|
-
|
|
53705
|
+
`${msg}
|
|
53644
53706
|
cwd=${displayPath(cwd)} realpath=${displayPath(safeRealpath(cwd))}
|
|
53645
53707
|
Please copy and paste this message into a new issue at https://github.com/vanillagreencom/kendex/issues/new` + (DEBUG ? ` and attach ${DEBUG_LOG_PATH}` : ` (rerun with CLAUDE_BRIDGE_DEBUG=1 to capture a debug log)`),
|
|
53646
53708
|
"warning"
|
|
@@ -54009,7 +54071,8 @@ function reapStaleQueuedResults(c) {
|
|
|
54009
54071
|
diagDump("stale_queued_tool_results_parked", { count: stale.length, stale });
|
|
54010
54072
|
appendIntegrityEntry("stale_queued_tool_results_parked", { count: stale.length, stale });
|
|
54011
54073
|
safeNotify(
|
|
54012
|
-
`
|
|
54074
|
+
`queued-results-parked=${JSON.stringify({ count: stale.length, tools: names })}
|
|
54075
|
+
Claude bridge: parked ${stale.length} early tool result(s) whose handler has not arrived (${names.slice(0, 6).join(", ")}${names.length > 6 ? ", \u2026" : ""}). A late handler can still consume them.`,
|
|
54013
54076
|
"warning"
|
|
54014
54077
|
);
|
|
54015
54078
|
}
|
|
@@ -54106,7 +54169,7 @@ function processStreamEvent(message, customToolNameToPi, model, c = ctx()) {
|
|
|
54106
54169
|
}
|
|
54107
54170
|
if (event.content_block?.type === "tool_use" && !isPiDispatchable(event.content_block.name, customToolNameToPi)) {
|
|
54108
54171
|
c.suppressedStreamIndexes.add(event.index);
|
|
54109
|
-
if (isForeignMcpTool(event.content_block.name)) c.
|
|
54172
|
+
if (isForeignMcpTool(event.content_block.name)) c.noteForeignMcpToolCall(event.content_block.id, event.content_block.name);
|
|
54110
54173
|
debug(`processStreamEvent: non-dispatchable tool ${event.content_block.name} [${event.content_block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
54111
54174
|
return;
|
|
54112
54175
|
}
|
|
@@ -54228,7 +54291,7 @@ function appendMissingToolUsesFromAssistant(assistantMsg, model, customToolNameT
|
|
|
54228
54291
|
continue;
|
|
54229
54292
|
}
|
|
54230
54293
|
if (!isPiDispatchable(block.name, customToolNameToPi)) {
|
|
54231
|
-
if (isForeignMcpTool(block.name)) c.
|
|
54294
|
+
if (isForeignMcpTool(block.name)) c.noteForeignMcpToolCall(block.id, block.name);
|
|
54232
54295
|
debug(`assistant message: non-dispatchable tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
54233
54296
|
continue;
|
|
54234
54297
|
}
|
|
@@ -54326,7 +54389,7 @@ function processAssistantMessage(message, model, customToolNameToPi, c = ctx())
|
|
|
54326
54389
|
continue;
|
|
54327
54390
|
}
|
|
54328
54391
|
if (!isPiDispatchable(block.name, customToolNameToPi)) {
|
|
54329
|
-
if (isForeignMcpTool(block.name)) c.
|
|
54392
|
+
if (isForeignMcpTool(block.name)) c.noteForeignMcpToolCall(block.id, block.name);
|
|
54330
54393
|
debug(`processAssistantMessage fallback: non-dispatchable tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
54331
54394
|
continue;
|
|
54332
54395
|
}
|
|
@@ -54456,6 +54519,52 @@ var BRIDGE_ACCOUNT_HOST = {
|
|
|
54456
54519
|
probeProfile: probeClaudeAccountProfile
|
|
54457
54520
|
};
|
|
54458
54521
|
|
|
54522
|
+
// src/billing-identity.ts
|
|
54523
|
+
var CLAUDE_BILLING_IDENTITY_SYMBOL = /* @__PURE__ */ Symbol.for("kendex.pi.claude-bridge.billing-identity.v1");
|
|
54524
|
+
var FIRST_PARTY = "firstParty";
|
|
54525
|
+
var BILLING_IDENTITY_LANES_SYMBOL = /* @__PURE__ */ Symbol.for("kendex.pi.claude-bridge.billing-identity-lanes.v1");
|
|
54526
|
+
function sharedBillingIdentityLanes() {
|
|
54527
|
+
const host = globalThis;
|
|
54528
|
+
let lanes = host[BILLING_IDENTITY_LANES_SYMBOL];
|
|
54529
|
+
if (!lanes) {
|
|
54530
|
+
lanes = /* @__PURE__ */ new Map();
|
|
54531
|
+
host[BILLING_IDENTITY_LANES_SYMBOL] = lanes;
|
|
54532
|
+
}
|
|
54533
|
+
return lanes;
|
|
54534
|
+
}
|
|
54535
|
+
function nonEmpty(value) {
|
|
54536
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
54537
|
+
}
|
|
54538
|
+
function loginEmailFrom(info) {
|
|
54539
|
+
if (info.apiProvider !== FIRST_PARTY) return void 0;
|
|
54540
|
+
if (nonEmpty(info.apiKeySource)) return void 0;
|
|
54541
|
+
return nonEmpty(info.email);
|
|
54542
|
+
}
|
|
54543
|
+
function makeBillingIdentityStore(lanes = /* @__PURE__ */ new Map()) {
|
|
54544
|
+
return {
|
|
54545
|
+
version: 1,
|
|
54546
|
+
currentLoginEmail: (sessionId) => lanes.get(sessionId)?.loginEmail,
|
|
54547
|
+
beginAttempt: (sessionId) => {
|
|
54548
|
+
const attempt = /* @__PURE__ */ Symbol("billing-identity-attempt");
|
|
54549
|
+
lanes.set(sessionId, { attempt });
|
|
54550
|
+
return (info) => {
|
|
54551
|
+
const current = lanes.get(sessionId);
|
|
54552
|
+
if (current?.attempt !== attempt) return;
|
|
54553
|
+
lanes.set(sessionId, { attempt, loginEmail: loginEmailFrom(info) });
|
|
54554
|
+
};
|
|
54555
|
+
},
|
|
54556
|
+
deleteLane: (sessionId) => lanes.delete(sessionId),
|
|
54557
|
+
clear: () => lanes.clear()
|
|
54558
|
+
};
|
|
54559
|
+
}
|
|
54560
|
+
var BRIDGE_BILLING_IDENTITY = makeBillingIdentityStore(sharedBillingIdentityLanes());
|
|
54561
|
+
function beginBillingIdentityAttempt() {
|
|
54562
|
+
return BRIDGE_BILLING_IDENTITY.beginAttempt(currentRequestLaneId());
|
|
54563
|
+
}
|
|
54564
|
+
function deleteBillingIdentityLane(sessionId) {
|
|
54565
|
+
BRIDGE_BILLING_IDENTITY.deleteLane(sessionId);
|
|
54566
|
+
}
|
|
54567
|
+
|
|
54459
54568
|
// src/bridge-commands.ts
|
|
54460
54569
|
var COMMANDS_REGISTERED_KEY = /* @__PURE__ */ Symbol.for("claude-bridge:commandsRegistered");
|
|
54461
54570
|
function commandCwd(ctx2) {
|
|
@@ -54545,10 +54654,11 @@ function noteFastModeDisabledReason(message, bridgeConfig) {
|
|
|
54545
54654
|
const text = FAST_MODE_DISABLED_REASON_TEXT[reason] ?? `unavailable (${reason})`;
|
|
54546
54655
|
safeNotify(`Pi Claude: fast mode is enabled in settings but Claude Code declined it \u2014 ${text}.`, "warning");
|
|
54547
54656
|
}
|
|
54548
|
-
async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridgeConfig, wasAborted, account, router, attemptFailureBox) {
|
|
54657
|
+
async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridgeConfig, wasAborted, recordBillingIdentity, account, router, attemptFailureBox) {
|
|
54549
54658
|
let capturedSessionId;
|
|
54550
54659
|
let failure;
|
|
54551
54660
|
let accountProbe;
|
|
54661
|
+
let accountInfoProbe;
|
|
54552
54662
|
const holdFailure = (next) => {
|
|
54553
54663
|
failure = next;
|
|
54554
54664
|
if (attemptFailureBox) attemptFailureBox.failure = next;
|
|
@@ -54626,9 +54736,13 @@ async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridg
|
|
|
54626
54736
|
capturedSessionId = message.session_id;
|
|
54627
54737
|
queryCtx.childSessionId = capturedSessionId;
|
|
54628
54738
|
noteFastModeDisabledReason(message, bridgeConfig);
|
|
54739
|
+
if (!accountInfoProbe) {
|
|
54740
|
+
accountInfoProbe = (async () => sdkQuery.accountInfo())();
|
|
54741
|
+
void accountInfoProbe.then((info) => recordBillingIdentity(info)).catch((error51) => debug("consumeQuery: billing identity probe rejected:", error51));
|
|
54742
|
+
}
|
|
54629
54743
|
if (account && router && !accountProbe) {
|
|
54630
54744
|
accountProbe = Promise.allSettled([
|
|
54631
|
-
|
|
54745
|
+
accountInfoProbe.then((info) => router.recordIdentity(account.profileId, {
|
|
54632
54746
|
email: info.email,
|
|
54633
54747
|
organization: info.organization,
|
|
54634
54748
|
subscriptionType: info.subscriptionType
|
|
@@ -55215,6 +55329,27 @@ function applyProviderRegistration(trigger) {
|
|
|
55215
55329
|
debug(`${trigger}: registerProvider threw; released stream guard for retry (kept primary):`, err);
|
|
55216
55330
|
}
|
|
55217
55331
|
}
|
|
55332
|
+
var HISTORY_REPLACED_PROMPT = "The conversation above was rewritten by Pi (compaction or history navigation). It is the complete current history, including the results of every tool call that has already run. Continue the turn from there, and do not repeat a tool call whose result is already above.";
|
|
55333
|
+
function restartContext(request) {
|
|
55334
|
+
return {
|
|
55335
|
+
...request.context,
|
|
55336
|
+
messages: [...request.context.messages, { role: "user", content: HISTORY_REPLACED_PROMPT, timestamp: Date.now() }]
|
|
55337
|
+
};
|
|
55338
|
+
}
|
|
55339
|
+
function onPiHistoryReplaced(event) {
|
|
55340
|
+
const activeSession = getSharedSession();
|
|
55341
|
+
const queryCtx = ctx();
|
|
55342
|
+
const running = queryCtx.activeQuery !== null;
|
|
55343
|
+
const restarts = running && !queryCtx.detachedFromSharedSession;
|
|
55344
|
+
if (running) {
|
|
55345
|
+
if (restarts) queryCtx.piHistoryReplaced = true;
|
|
55346
|
+
reportToolResultMismatch(queryCtx, event, activeSession?.cwd ?? process.cwd(), { expectedInterruption: restarts });
|
|
55347
|
+
}
|
|
55348
|
+
if (activeSession) {
|
|
55349
|
+
debug(`${event}: marking needsRebuild on session ${activeSession.sessionId.slice(0, 8)}`);
|
|
55350
|
+
markSessionForRebuild({ forceRotate: restarts });
|
|
55351
|
+
}
|
|
55352
|
+
}
|
|
55218
55353
|
function streamClaudeAgentSdk(model, context, options) {
|
|
55219
55354
|
return runInRequestLane(options?.sessionId, () => streamClaudeAgentSdkInLane(model, context, options));
|
|
55220
55355
|
}
|
|
@@ -55226,12 +55361,30 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55226
55361
|
if (!ephemeralLane) return;
|
|
55227
55362
|
deleteSharedSessionLane(laneId);
|
|
55228
55363
|
deleteQueryLane(laneId);
|
|
55364
|
+
deleteBillingIdentityLane(laneId);
|
|
55229
55365
|
};
|
|
55230
55366
|
const lastMsgRole = context.messages[context.messages.length - 1]?.role;
|
|
55231
55367
|
const cwd = options?.cwd ?? process.cwd();
|
|
55232
55368
|
debug(`provider: streamClaudeAgentSdk called, activeQuery=${!!ctx().activeQuery}, lastMsgRole=${lastMsgRole}, isReentrant=${ctx().activeQuery !== null}`);
|
|
55233
55369
|
if (ctx().activeQuery) {
|
|
55234
55370
|
const queryCtx = ctx();
|
|
55371
|
+
if (queryCtx.piHistoryReplaced) {
|
|
55372
|
+
if (queryCtx.childSideCalls.size > 0) {
|
|
55373
|
+
if (!queryCtx.reportedHistoryRestartDecline) {
|
|
55374
|
+
queryCtx.reportedHistoryRestartDecline = true;
|
|
55375
|
+
const names = [...new Set([...queryCtx.childSideCalls.values()].map((call) => call.name))];
|
|
55376
|
+
debug(`provider: pi replaced this query's history, but ${queryCtx.childSideCalls.size} child-executed call(s) are absent from pi's context; not restarting (${names.join(", ")})`);
|
|
55377
|
+
appendIntegrityEntry("history_restart_declined", { reason: "child-executed calls pi's history cannot carry", count: queryCtx.childSideCalls.size, names });
|
|
55378
|
+
}
|
|
55379
|
+
} else {
|
|
55380
|
+
queryCtx.piHistoryReplaced = false;
|
|
55381
|
+
queryCtx.restartRequest = { model, context, options, stream };
|
|
55382
|
+
queryCtx.currentPiStream = null;
|
|
55383
|
+
debug(`provider: pi replaced this query's history; restarting from ${context.messages.length} message(s)`);
|
|
55384
|
+
abortSdkQuery(queryCtx.activeQuery);
|
|
55385
|
+
return stream;
|
|
55386
|
+
}
|
|
55387
|
+
}
|
|
55235
55388
|
queryCtx.currentPiStream = stream;
|
|
55236
55389
|
queryCtx.resetTurnState(model);
|
|
55237
55390
|
queryCtx.callbackGeneration += 1;
|
|
@@ -55326,6 +55479,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55326
55479
|
});
|
|
55327
55480
|
return stream;
|
|
55328
55481
|
}
|
|
55482
|
+
const recordBillingIdentity = beginBillingIdentityAttempt();
|
|
55329
55483
|
if (!hasClaudeCredentials() && !resolveClaudeAccountRouter()) {
|
|
55330
55484
|
try {
|
|
55331
55485
|
applyProviderRegistration("pre-spawn");
|
|
@@ -55365,6 +55519,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55365
55519
|
ctx().pendingToolCalls.clear();
|
|
55366
55520
|
ctx().pendingResults.clear();
|
|
55367
55521
|
ctx().reapedResults.clear();
|
|
55522
|
+
ctx().childSideCalls.clear();
|
|
55368
55523
|
ctx().forwardedToolCallIds.clear();
|
|
55369
55524
|
ctx().deadToolCallIds.clear();
|
|
55370
55525
|
ctx().callbackGeneration = 0;
|
|
@@ -55373,6 +55528,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55373
55528
|
ctx().resetToolTracking();
|
|
55374
55529
|
ctx().latestCursor = 0;
|
|
55375
55530
|
ctx().committedOutput = false;
|
|
55531
|
+
ctx().piHistoryReplaced = false;
|
|
55532
|
+
ctx().reportedHistoryRestartDecline = false;
|
|
55376
55533
|
ctx().detachedFromSharedSession = isReentrant;
|
|
55377
55534
|
const router = resolveClaudeAccountRouter();
|
|
55378
55535
|
const rotationOptions = options;
|
|
@@ -55496,6 +55653,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55496
55653
|
`prompt=${promptText.slice(0, 60)}${promptBlocks ? " [+images]" : ""}`
|
|
55497
55654
|
);
|
|
55498
55655
|
let wasAborted = false;
|
|
55656
|
+
let reentryStream = stream;
|
|
55499
55657
|
let streamIdleTimedOut = false;
|
|
55500
55658
|
let retryRequested = false;
|
|
55501
55659
|
let retryFailure;
|
|
@@ -55505,7 +55663,9 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55505
55663
|
const attemptFailure = {};
|
|
55506
55664
|
const persistSession = (next) => {
|
|
55507
55665
|
if (isReentrant || foreignContext) return;
|
|
55508
|
-
|
|
55666
|
+
const restartPending = abortCtx.restartRequest !== null;
|
|
55667
|
+
const replaced = next && (abortCtx.piHistoryReplaced || restartPending) ? { ...next, needsRebuild: true, ...restartPending ? { forceRotate: true } : {} } : next;
|
|
55668
|
+
setSharedSession(replaced && conversationFp ? { conversationFingerprint: conversationFp, ...replaced } : replaced);
|
|
55509
55669
|
};
|
|
55510
55670
|
const markRebuildForThisQuery = (opts = {}) => {
|
|
55511
55671
|
if (isReentrant || foreignContext) return;
|
|
@@ -55525,14 +55685,6 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55525
55685
|
safeRouterCall("recordFailure", () => router.recordFailure(account.profileId, failure.kind, queryModel.id));
|
|
55526
55686
|
accountFailureRecorded = true;
|
|
55527
55687
|
};
|
|
55528
|
-
const requestAbort = () => {
|
|
55529
|
-
void sdkQuery.interrupt().catch(() => {
|
|
55530
|
-
});
|
|
55531
|
-
try {
|
|
55532
|
-
sdkQuery.close();
|
|
55533
|
-
} catch {
|
|
55534
|
-
}
|
|
55535
|
-
};
|
|
55536
55688
|
const requestRotation = (failure) => {
|
|
55537
55689
|
recordAttemptFailure(failure);
|
|
55538
55690
|
const committed = abortCtx.committedOutput || attemptBuffer?.hasCommittedOutput === true;
|
|
@@ -55573,7 +55725,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55573
55725
|
debug("provider: stream idle timeout", `model=${queryModel.id}`, `timeout=${timeoutMs}`, `idle=${idleMs}`);
|
|
55574
55726
|
const idleFailure = { kind: "network", message: errorMessage };
|
|
55575
55727
|
if (requestRotation(idleFailure)) {
|
|
55576
|
-
|
|
55728
|
+
abortSdkQuery(sdkQuery);
|
|
55577
55729
|
return;
|
|
55578
55730
|
}
|
|
55579
55731
|
abortCtx.handledTerminalError = true;
|
|
@@ -55601,7 +55753,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55601
55753
|
abortCtx.currentPiStream?.push({ type: "error", reason: "error", error: abortCtx.turnOutput });
|
|
55602
55754
|
abortCtx.currentPiStream?.end();
|
|
55603
55755
|
abortCtx.currentPiStream = null;
|
|
55604
|
-
|
|
55756
|
+
abortSdkQuery(sdkQuery);
|
|
55605
55757
|
},
|
|
55606
55758
|
timeoutMs: streamIdleTimeoutMs
|
|
55607
55759
|
}) : null;
|
|
@@ -55619,7 +55771,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55619
55771
|
const drained = drainPendingToolCalls(abortCtx, "abort");
|
|
55620
55772
|
if (drained > 0) debug(`provider: abort drained ${drained} waiting MCP handler(s) as errors`);
|
|
55621
55773
|
abortCtx.pendingResults.clear();
|
|
55622
|
-
|
|
55774
|
+
abortSdkQuery(sdkQuery);
|
|
55623
55775
|
});
|
|
55624
55776
|
if (options?.signal) {
|
|
55625
55777
|
if (options.signal.aborted) onAbort();
|
|
@@ -55651,8 +55803,12 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55651
55803
|
abortCtx.currentPiStream?.end();
|
|
55652
55804
|
abortCtx.currentPiStream = null;
|
|
55653
55805
|
};
|
|
55654
|
-
consumeQuery(sdkQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, account, router, attemptFailure).then(async ({ capturedSessionId, failure }) => {
|
|
55806
|
+
consumeQuery(sdkQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, recordBillingIdentity, account, router, attemptFailure).then(async ({ capturedSessionId, failure }) => {
|
|
55655
55807
|
debug(`provider: consumeQuery completed, stopReason=${abortCtx.turnOutput?.stopReason}, failure=${failure?.kind ?? "none"}, aborted=${wasAborted}`);
|
|
55808
|
+
if (abortCtx.restartRequest) {
|
|
55809
|
+
debug("provider: query ended for a history restart; leaving the outcome to the replacement query");
|
|
55810
|
+
return;
|
|
55811
|
+
}
|
|
55656
55812
|
if (streamIdleTimedOut) {
|
|
55657
55813
|
dropDeferredUserMessages("stream-idle-timeout-completion");
|
|
55658
55814
|
debug(`provider: stream idle timeout ${retryRequested ? "queued account rotation" : "already surfaced"}; skipping normal completion`);
|
|
@@ -55704,7 +55860,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55704
55860
|
abortCtx.activeQuery = contQuery;
|
|
55705
55861
|
debug(`provider: continuation query, model=${queryModel.id}, resume=${resumeId.slice(0, 8)}, account=${account?.label ?? "legacy"}, prompt=${steerPreview}`);
|
|
55706
55862
|
try {
|
|
55707
|
-
const continuation = await consumeQuery(contQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, account, router);
|
|
55863
|
+
const continuation = await consumeQuery(contQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, recordBillingIdentity, account, router);
|
|
55864
|
+
if (abortCtx.restartRequest) break;
|
|
55708
55865
|
if (continuation.failure) {
|
|
55709
55866
|
recordAttemptFailure(continuation.failure);
|
|
55710
55867
|
if (!abortCtx.handledTerminalError) surfaceFailure(continuation.failure);
|
|
@@ -55719,6 +55876,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55719
55876
|
persistSession({ sessionId: sid, cursor: activeSession2?.cursor ?? 0, cwd, ...accountScope });
|
|
55720
55877
|
}
|
|
55721
55878
|
} catch (contError) {
|
|
55879
|
+
if (abortCtx.restartRequest) break;
|
|
55722
55880
|
debug(`provider: continuation query error:`, contError);
|
|
55723
55881
|
const continuationFailure = {
|
|
55724
55882
|
kind: classifyClaudeFailure(contError),
|
|
@@ -55740,6 +55898,10 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55740
55898
|
finalizeCurrentStream(abortCtx.turnOutput?.stopReason, abortCtx);
|
|
55741
55899
|
}).catch((error51) => {
|
|
55742
55900
|
debug(`provider: query error, model=${queryModel.id}, aborted=${Boolean(options?.signal?.aborted)}, error=`, error51);
|
|
55901
|
+
if (abortCtx.restartRequest) {
|
|
55902
|
+
debug("provider: query error while a history restart was pending; suppressed");
|
|
55903
|
+
return;
|
|
55904
|
+
}
|
|
55743
55905
|
const suppressDuplicateError = abortCtx.handledTerminalError || streamIdleTimedOut && !retryRequested;
|
|
55744
55906
|
if (wasAborted || options?.signal?.aborted) {
|
|
55745
55907
|
markRebuildForThisQuery({ forceRotate: true });
|
|
@@ -55764,8 +55926,26 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55764
55926
|
if (options?.signal) options.signal.removeEventListener("abort", onAbort);
|
|
55765
55927
|
const cause = toolCallDrainCause({ wasAborted, signalAborted: options?.signal?.aborted, streamIdleTimedOut });
|
|
55766
55928
|
teardownQuery(abortCtx, sdkQuery, cause, cwd, isReentrant);
|
|
55767
|
-
sdkQuery
|
|
55929
|
+
closeSdkQuery(sdkQuery);
|
|
55768
55930
|
}).then(async () => {
|
|
55931
|
+
const restart = abortCtx.restartRequest;
|
|
55932
|
+
if (restart) {
|
|
55933
|
+
abortCtx.restartRequest = null;
|
|
55934
|
+
reentryStream = restart.stream;
|
|
55935
|
+
if (wasAborted || options?.signal?.aborted || restart.options?.signal?.aborted) {
|
|
55936
|
+
debug("provider: abort before the history restart \u2014 terminating the stream without restarting");
|
|
55937
|
+
abortCtx.resetTurnState(restart.model);
|
|
55938
|
+
abortCtx.turnOutput.stopReason = "aborted";
|
|
55939
|
+
abortCtx.turnOutput.errorMessage = "Operation aborted";
|
|
55940
|
+
reentryStream.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
|
|
55941
|
+
reentryStream.end();
|
|
55942
|
+
return;
|
|
55943
|
+
}
|
|
55944
|
+
debug(`provider: restarting query on replaced history, ${restart.context.messages.length} pi message(s)`);
|
|
55945
|
+
for await (const event of streamClaudeAgentSdk(restart.model, restartContext(restart), restart.options)) reentryStream.push(event);
|
|
55946
|
+
reentryStream.end();
|
|
55947
|
+
return;
|
|
55948
|
+
}
|
|
55769
55949
|
if (!retryRequested) return;
|
|
55770
55950
|
if (wasAborted || options?.signal?.aborted) {
|
|
55771
55951
|
debug("provider: abort after queued account retry \u2014 terminating stream without retrying");
|
|
@@ -55773,8 +55953,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55773
55953
|
abortCtx.turnOutput.stopReason = "aborted";
|
|
55774
55954
|
abortCtx.turnOutput.errorMessage = "Operation aborted";
|
|
55775
55955
|
}
|
|
55776
|
-
|
|
55777
|
-
|
|
55956
|
+
reentryStream.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
|
|
55957
|
+
reentryStream.end();
|
|
55778
55958
|
return;
|
|
55779
55959
|
}
|
|
55780
55960
|
debug(`provider: starting account retry after ${retryFailure?.kind ?? "failure"}; excluded=${[...rotationState.excludedProfileIds].join(",")}`);
|
|
@@ -55782,16 +55962,22 @@ function streamClaudeAgentSdkInLane(model, context, options) {
|
|
|
55782
55962
|
...options ?? {},
|
|
55783
55963
|
[ROTATION_STATE_KEY]: rotationState
|
|
55784
55964
|
});
|
|
55785
|
-
for await (const event of retryStream)
|
|
55786
|
-
|
|
55965
|
+
for await (const event of retryStream) reentryStream.push(event);
|
|
55966
|
+
reentryStream.end();
|
|
55787
55967
|
}).catch((error51) => {
|
|
55788
|
-
debug("provider:
|
|
55968
|
+
debug("provider: re-entry pipeline failed:", error51);
|
|
55969
|
+
const restart = abortCtx.restartRequest;
|
|
55970
|
+
if (restart) {
|
|
55971
|
+
abortCtx.restartRequest = null;
|
|
55972
|
+
reentryStream = restart.stream;
|
|
55973
|
+
abortCtx.resetTurnState(restart.model);
|
|
55974
|
+
}
|
|
55789
55975
|
if (abortCtx.turnOutput) {
|
|
55790
55976
|
abortCtx.turnOutput.stopReason = "error";
|
|
55791
55977
|
abortCtx.turnOutput.errorMessage = error51 instanceof Error ? error51.message : String(error51);
|
|
55792
55978
|
}
|
|
55793
|
-
|
|
55794
|
-
|
|
55979
|
+
reentryStream.push({ type: "error", reason: "error", error: abortCtx.turnOutput });
|
|
55980
|
+
reentryStream.end();
|
|
55795
55981
|
}).finally(releaseEphemeralLane);
|
|
55796
55982
|
return stream;
|
|
55797
55983
|
}
|
|
@@ -55809,6 +55995,7 @@ function index_default(pi2) {
|
|
|
55809
55995
|
if (claimPrimaryInstance()) {
|
|
55810
55996
|
const host = globalThis;
|
|
55811
55997
|
host[CLAUDE_BRIDGE_ACCOUNT_HOST_SYMBOL] = BRIDGE_ACCOUNT_HOST;
|
|
55998
|
+
host[CLAUDE_BILLING_IDENTITY_SYMBOL] = BRIDGE_BILLING_IDENTITY;
|
|
55812
55999
|
}
|
|
55813
56000
|
const clearSession = (event) => {
|
|
55814
56001
|
const activeSession = getSharedSession();
|
|
@@ -55834,23 +56021,14 @@ function index_default(pi2) {
|
|
|
55834
56021
|
});
|
|
55835
56022
|
deleteSharedSessionLane(sessionId);
|
|
55836
56023
|
deleteQueryLane(sessionId);
|
|
56024
|
+
deleteBillingIdentityLane(sessionId);
|
|
55837
56025
|
});
|
|
55838
56026
|
pi2.on("message_end", (event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => {
|
|
55839
56027
|
const message = event.message;
|
|
55840
56028
|
if (message?.role === "assistant" && message.provider === PROVIDER_ID) schedulePersistSharedSession(ctx2);
|
|
55841
56029
|
}));
|
|
55842
|
-
|
|
55843
|
-
|
|
55844
|
-
if (ctx().activeQuery) {
|
|
55845
|
-
reportToolResultMismatch(ctx(), event, activeSession?.cwd ?? process.cwd());
|
|
55846
|
-
}
|
|
55847
|
-
if (activeSession) {
|
|
55848
|
-
debug(`${event}: marking needsRebuild on session ${activeSession.sessionId.slice(0, 8)}`);
|
|
55849
|
-
markSessionForRebuild();
|
|
55850
|
-
}
|
|
55851
|
-
};
|
|
55852
|
-
pi2.on("session_compact", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => markRebuild("session_compact")));
|
|
55853
|
-
pi2.on("session_tree", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => markRebuild("session_tree")));
|
|
56030
|
+
pi2.on("session_compact", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => onPiHistoryReplaced("session_compact")));
|
|
56031
|
+
pi2.on("session_tree", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => onPiHistoryReplaced("session_tree")));
|
|
55854
56032
|
applyProviderRegistration("load");
|
|
55855
56033
|
}
|
|
55856
56034
|
export {
|
|
@@ -55864,6 +56042,7 @@ export {
|
|
|
55864
56042
|
CONNECTOR_WRITE_TOOLS,
|
|
55865
56043
|
DEFAULT_STREAM_IDLE_TIMEOUT_MS,
|
|
55866
56044
|
DISALLOWED_BUILTIN_TOOLS,
|
|
56045
|
+
HISTORY_REPLACED_PROMPT,
|
|
55867
56046
|
INTEGRITY_CUSTOM_TYPE,
|
|
55868
56047
|
NATIVE_PROVIDER_UNSUPPORTED_MESSAGE,
|
|
55869
56048
|
RetryEventBuffer,
|
|
@@ -55922,6 +56101,7 @@ export {
|
|
|
55922
56101
|
mapToolName,
|
|
55923
56102
|
normalizeRateLimitUtilization,
|
|
55924
56103
|
noteChildExecutedToolResults,
|
|
56104
|
+
onPiHistoryReplaced,
|
|
55925
56105
|
planDeferredUserReplay,
|
|
55926
56106
|
planIncrementalPromptBatch,
|
|
55927
56107
|
preflightClaudeExecutable,
|