billion-context 0.1.72 → 0.1.73-pr.440.290
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/index.js +347 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -51466,8 +51466,26 @@ function recordUsage(ctx, usage, round) {
|
|
|
51466
51466
|
async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adapter, systemPrompt, signal) {
|
|
51467
51467
|
let activeClearTimer = null;
|
|
51468
51468
|
let currentUpstream = upstream;
|
|
51469
|
+
let roundBody = requestBody;
|
|
51469
51470
|
const coreMessages = [...ctx.messages];
|
|
51470
51471
|
let degradedRetried = false;
|
|
51472
|
+
let truncationRetried = false;
|
|
51473
|
+
const fetchUpstream = (body) => fetchWithRetry(
|
|
51474
|
+
requestOptions.url,
|
|
51475
|
+
{
|
|
51476
|
+
method: "POST",
|
|
51477
|
+
headers: requestOptions.headers,
|
|
51478
|
+
body: JSON.stringify(body),
|
|
51479
|
+
...ctx.proxyUrl ? { dispatcher: proxyDispatcher(ctx.proxyUrl) } : {}
|
|
51480
|
+
},
|
|
51481
|
+
void 0,
|
|
51482
|
+
signal,
|
|
51483
|
+
(info) => {
|
|
51484
|
+
const lc = lastCompressSuffix(ctx.session.lastCompress);
|
|
51485
|
+
ctx.log(`[acp-proxy: upstream rejected replay (HTTP ${info.status}: ${info.detail.slice(0, 120)}); likely provider risk-control \u2014 retrying in ${info.delayMs}ms (attempt ${info.attempt}/${info.maxAttempts})${lc}]`);
|
|
51486
|
+
log("warn", `[acp-loop] upstream rejected replay (HTTP ${info.status}); retrying in ${info.delayMs}ms (attempt ${info.attempt}/${info.maxAttempts})${lc}`);
|
|
51487
|
+
}
|
|
51488
|
+
);
|
|
51471
51489
|
try {
|
|
51472
51490
|
for (let round = 1; round <= MAX_LOOP_ROUNDS; round++) {
|
|
51473
51491
|
if (signal?.aborted) break;
|
|
@@ -51480,50 +51498,93 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
51480
51498
|
let finishReason;
|
|
51481
51499
|
let sawDone = false;
|
|
51482
51500
|
let suppressCompletion = false;
|
|
51483
|
-
|
|
51484
|
-
|
|
51485
|
-
|
|
51486
|
-
|
|
51487
|
-
|
|
51488
|
-
|
|
51489
|
-
|
|
51490
|
-
|
|
51491
|
-
|
|
51492
|
-
|
|
51493
|
-
|
|
51494
|
-
|
|
51495
|
-
|
|
51496
|
-
|
|
51497
|
-
|
|
51498
|
-
|
|
51499
|
-
|
|
51500
|
-
|
|
51501
|
-
|
|
51502
|
-
if (
|
|
51503
|
-
if (
|
|
51504
|
-
|
|
51505
|
-
|
|
51506
|
-
|
|
51507
|
-
|
|
51508
|
-
|
|
51509
|
-
|
|
51510
|
-
|
|
51511
|
-
|
|
51512
|
-
|
|
51513
|
-
|
|
51514
|
-
|
|
51515
|
-
|
|
51516
|
-
|
|
51517
|
-
|
|
51518
|
-
|
|
51519
|
-
|
|
51520
|
-
|
|
51521
|
-
|
|
51522
|
-
|
|
51523
|
-
|
|
51524
|
-
|
|
51501
|
+
let truncatedDone = false;
|
|
51502
|
+
let forwardedAny = false;
|
|
51503
|
+
const fwd = (chunk) => {
|
|
51504
|
+
forwardedAny = true;
|
|
51505
|
+
return chunk;
|
|
51506
|
+
};
|
|
51507
|
+
for (; ; ) {
|
|
51508
|
+
assistantText = "";
|
|
51509
|
+
assistantReasoning = "";
|
|
51510
|
+
reasoningSegments.length = 0;
|
|
51511
|
+
reasoningSealed = true;
|
|
51512
|
+
calls.length = 0;
|
|
51513
|
+
usage = {};
|
|
51514
|
+
finishReason = void 0;
|
|
51515
|
+
sawDone = false;
|
|
51516
|
+
suppressCompletion = false;
|
|
51517
|
+
truncatedDone = false;
|
|
51518
|
+
forwardedAny = false;
|
|
51519
|
+
for await (const ev of adapter.parseStream(currentUpstream, round)) {
|
|
51520
|
+
if (signal?.aborted) break;
|
|
51521
|
+
if (ev.kind === "text") {
|
|
51522
|
+
assistantText += ev.delta;
|
|
51523
|
+
if (!ctx.textProtocol && ev.raw) {
|
|
51524
|
+
yield fwd(ev.raw);
|
|
51525
|
+
} else if (!ctx.textProtocol && round > 1 && ev.delta.length > 0) {
|
|
51526
|
+
yield fwd(adapter.emitText(ev.delta));
|
|
51527
|
+
}
|
|
51528
|
+
} else if (ev.kind === "reasoning") {
|
|
51529
|
+
assistantReasoning += ev.delta;
|
|
51530
|
+
let seg = reasoningSegments[reasoningSegments.length - 1];
|
|
51531
|
+
if (reasoningSealed || !seg) {
|
|
51532
|
+
seg = { text: "", signature: "" };
|
|
51533
|
+
reasoningSegments.push(seg);
|
|
51534
|
+
reasoningSealed = false;
|
|
51535
|
+
}
|
|
51536
|
+
seg.text += ev.delta;
|
|
51537
|
+
if (ev.signature) seg.signature += ev.signature;
|
|
51538
|
+
if (ev.blockEnd) reasoningSealed = true;
|
|
51539
|
+
if (!ctx.textProtocol) {
|
|
51540
|
+
if (ev.raw) {
|
|
51541
|
+
yield fwd(ev.raw);
|
|
51542
|
+
} else if (round > 1 && ev.delta.length > 0 && adapter.emitReasoning) {
|
|
51543
|
+
yield fwd(adapter.emitReasoning(ev.delta));
|
|
51544
|
+
}
|
|
51545
|
+
}
|
|
51546
|
+
} else if (ev.kind === "tool_call") {
|
|
51547
|
+
calls.push({ name: ev.name, callId: ev.callId, arguments: ev.arguments, passthrough: ev.passthrough });
|
|
51548
|
+
} else if (ev.kind === "usage") {
|
|
51549
|
+
usage = {
|
|
51550
|
+
inputTokens: ev.inputTokens,
|
|
51551
|
+
outputTokens: ev.outputTokens,
|
|
51552
|
+
cachedTokens: ev.cachedTokens
|
|
51553
|
+
};
|
|
51554
|
+
} else if (ev.kind === "done") {
|
|
51555
|
+
sawDone = true;
|
|
51556
|
+
finishReason = ev.finishReason;
|
|
51557
|
+
suppressCompletion = ev.suppressCompletion === true;
|
|
51558
|
+
truncatedDone = ev.truncated === true;
|
|
51559
|
+
} else if (ev.kind === "meta") {
|
|
51560
|
+
if (round === 1 || !ev.firstRoundOnly) {
|
|
51561
|
+
yield fwd(ev.chunk);
|
|
51562
|
+
}
|
|
51563
|
+
}
|
|
51564
|
+
}
|
|
51565
|
+
if ((!sawDone || truncatedDone) && !forwardedAny && calls.length === 0 && !(ctx.textProtocol && assistantText.length > 0) && !signal?.aborted && !truncationRetried) {
|
|
51566
|
+
truncationRetried = true;
|
|
51567
|
+
ctx.log(`[acp-loop] round ${round}: upstream truncated before any content reached the client; retrying fetch once`);
|
|
51568
|
+
try {
|
|
51569
|
+
const respResult2 = await fetchUpstream(roundBody);
|
|
51570
|
+
if (!respResult2.response.body) {
|
|
51571
|
+
respResult2.clearTimer();
|
|
51572
|
+
throw new UpstreamHttpError(respResult2.response.status, "(empty response body)", 1);
|
|
51573
|
+
}
|
|
51574
|
+
currentUpstream = respResult2.response.body;
|
|
51575
|
+
if (activeClearTimer) activeClearTimer();
|
|
51576
|
+
activeClearTimer = respResult2.clearTimer;
|
|
51577
|
+
continue;
|
|
51578
|
+
} catch (e) {
|
|
51579
|
+
if (e instanceof UpstreamHttpError) {
|
|
51580
|
+
const suffix = e.attempts > 1 ? ` after ${e.attempts} attempt(s)` : "";
|
|
51581
|
+
ctx.log(`[acp-loop] round ${round}: truncation retry failed (upstream error ${e.status}${suffix}: ${e.body.slice(0, 200)})`);
|
|
51582
|
+
} else {
|
|
51583
|
+
ctx.log(`[acp-loop] round ${round}: truncation retry failed (${e instanceof Error ? e.message : String(e)})`);
|
|
51584
|
+
}
|
|
51525
51585
|
}
|
|
51526
51586
|
}
|
|
51587
|
+
break;
|
|
51527
51588
|
}
|
|
51528
51589
|
if (usage.inputTokens !== void 0 || usage.outputTokens !== void 0 || usage.cachedTokens !== void 0) {
|
|
51529
51590
|
recordUsage(ctx, usage, round);
|
|
@@ -51657,7 +51718,6 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
51657
51718
|
const partialReasoning = assistantReasoning.length;
|
|
51658
51719
|
const msg = `upstream stream truncated (no completion event; round ${round}, ${partialText} text chars + ${partialReasoning} reasoning chars received)`;
|
|
51659
51720
|
ctx.log(`[acp-loop] round ${round}: ${msg}`);
|
|
51660
|
-
log("error", `[acp-loop] ${msg}`);
|
|
51661
51721
|
yield adapter.emitError(msg);
|
|
51662
51722
|
return;
|
|
51663
51723
|
}
|
|
@@ -51674,22 +51734,6 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
51674
51734
|
}
|
|
51675
51735
|
ctx.log(`[acp-loop] round ${round}: proxy tool executed; re-requesting so the model sees the result`);
|
|
51676
51736
|
if (signal?.aborted) break;
|
|
51677
|
-
const fetchUpstream = (body) => fetchWithRetry(
|
|
51678
|
-
requestOptions.url,
|
|
51679
|
-
{
|
|
51680
|
-
method: "POST",
|
|
51681
|
-
headers: requestOptions.headers,
|
|
51682
|
-
body: JSON.stringify(body),
|
|
51683
|
-
...ctx.proxyUrl ? { dispatcher: proxyDispatcher(ctx.proxyUrl) } : {}
|
|
51684
|
-
},
|
|
51685
|
-
void 0,
|
|
51686
|
-
signal,
|
|
51687
|
-
(info) => {
|
|
51688
|
-
const lc = lastCompressSuffix(ctx.session.lastCompress);
|
|
51689
|
-
ctx.log(`[acp-proxy: upstream rejected replay (HTTP ${info.status}: ${info.detail.slice(0, 120)}); likely provider risk-control \u2014 retrying in ${info.delayMs}ms (attempt ${info.attempt}/${info.maxAttempts})${lc}]`);
|
|
51690
|
-
log("warn", `[acp-loop] upstream rejected replay (HTTP ${info.status}); retrying in ${info.delayMs}ms (attempt ${info.attempt}/${info.maxAttempts})${lc}`);
|
|
51691
|
-
}
|
|
51692
|
-
);
|
|
51693
51737
|
let newBody = adapter.buildRequest(coreMessages, systemPrompt, requestBody);
|
|
51694
51738
|
if (process.env.ACP_DUMP_BODY === "1") {
|
|
51695
51739
|
try {
|
|
@@ -51732,6 +51776,7 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
51732
51776
|
return;
|
|
51733
51777
|
}
|
|
51734
51778
|
currentUpstream = respResult.response.body;
|
|
51779
|
+
roundBody = newBody;
|
|
51735
51780
|
if (activeClearTimer) activeClearTimer();
|
|
51736
51781
|
activeClearTimer = respResult.clearTimer;
|
|
51737
51782
|
}
|
|
@@ -52056,6 +52101,20 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
52056
52101
|
let responseObj = null;
|
|
52057
52102
|
let terminalRaw = null;
|
|
52058
52103
|
let terminalKind = null;
|
|
52104
|
+
let createdForwarded = false;
|
|
52105
|
+
let createdRespId = null;
|
|
52106
|
+
const ensureCreated = () => {
|
|
52107
|
+
if (createdForwarded) return null;
|
|
52108
|
+
createdForwarded = true;
|
|
52109
|
+
if (!createdRespId) createdRespId = `resp-proxy-${Date.now()}`;
|
|
52110
|
+
return Buffer.from(
|
|
52111
|
+
`event: response.created
|
|
52112
|
+
data: ${JSON.stringify({ type: "response.created", response: { id: createdRespId, status: "in_progress", output: [] } })}
|
|
52113
|
+
|
|
52114
|
+
`,
|
|
52115
|
+
"utf8"
|
|
52116
|
+
);
|
|
52117
|
+
};
|
|
52059
52118
|
return {
|
|
52060
52119
|
buildRequest(coreMessages, systemPrompt, requestBody) {
|
|
52061
52120
|
const customToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -52110,6 +52169,11 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
52110
52169
|
outputIndex = Math.max(outputIndex, obj.output_index + 1);
|
|
52111
52170
|
}
|
|
52112
52171
|
if (type === "response.created" || type === "response.in_progress") {
|
|
52172
|
+
if (type === "response.created") {
|
|
52173
|
+
const resp = obj.response;
|
|
52174
|
+
if (resp && typeof resp.id === "string") createdRespId = resp.id;
|
|
52175
|
+
if (round === 1) createdForwarded = true;
|
|
52176
|
+
}
|
|
52113
52177
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
52114
52178
|
} else if (type === "response.output_item.added") {
|
|
52115
52179
|
const item = obj.item;
|
|
@@ -52243,7 +52307,7 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
52243
52307
|
}
|
|
52244
52308
|
}
|
|
52245
52309
|
if (!terminalKind) {
|
|
52246
|
-
yield { kind: "done", finishReason: "failed" };
|
|
52310
|
+
yield { kind: "done", finishReason: "failed", truncated: true };
|
|
52247
52311
|
}
|
|
52248
52312
|
},
|
|
52249
52313
|
emitText(delta) {
|
|
@@ -52266,18 +52330,22 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
52266
52330
|
return terminalRaw;
|
|
52267
52331
|
}
|
|
52268
52332
|
if (!responseObj && opts?.finishReason === "failed") {
|
|
52333
|
+
const parts = [];
|
|
52334
|
+
const created = ensureCreated();
|
|
52335
|
+
if (created) parts.push(created);
|
|
52269
52336
|
const failed = {
|
|
52270
|
-
id: `resp-error-${Date.now()}`,
|
|
52337
|
+
id: createdRespId ?? `resp-error-${Date.now()}`,
|
|
52271
52338
|
status: "failed",
|
|
52272
52339
|
error: { code: "server_error", message: "upstream returned no response" }
|
|
52273
52340
|
};
|
|
52274
|
-
|
|
52341
|
+
parts.push(Buffer.from(
|
|
52275
52342
|
`event: response.failed
|
|
52276
52343
|
data: ${JSON.stringify({ type: "response.failed", response: failed })}
|
|
52277
52344
|
|
|
52278
52345
|
`,
|
|
52279
52346
|
"utf8"
|
|
52280
|
-
);
|
|
52347
|
+
));
|
|
52348
|
+
return Buffer.concat(parts);
|
|
52281
52349
|
}
|
|
52282
52350
|
let resp = responseObj ? { ...responseObj } : { id: `resp-proxy-${Date.now()}`, status: "completed", output: [] };
|
|
52283
52351
|
if (opts?.usage) {
|
|
@@ -52297,18 +52365,22 @@ data: ${JSON.stringify({ type: "response.failed", response: failed })}
|
|
|
52297
52365
|
return buildCompleted(resp);
|
|
52298
52366
|
},
|
|
52299
52367
|
emitError(message) {
|
|
52368
|
+
const parts = [];
|
|
52369
|
+
const created = ensureCreated();
|
|
52370
|
+
if (created) parts.push(created);
|
|
52300
52371
|
const resp = {
|
|
52301
|
-
id: `resp-error-${Date.now()}`,
|
|
52372
|
+
id: createdRespId ?? `resp-error-${Date.now()}`,
|
|
52302
52373
|
status: "failed",
|
|
52303
52374
|
error: { code: "server_error", message }
|
|
52304
52375
|
};
|
|
52305
|
-
|
|
52376
|
+
parts.push(Buffer.from(
|
|
52306
52377
|
`event: response.failed
|
|
52307
52378
|
data: ${JSON.stringify({ type: "response.failed", response: resp })}
|
|
52308
52379
|
|
|
52309
52380
|
`,
|
|
52310
52381
|
"utf8"
|
|
52311
|
-
);
|
|
52382
|
+
));
|
|
52383
|
+
return Buffer.concat(parts);
|
|
52312
52384
|
},
|
|
52313
52385
|
extractTextTriggers(text) {
|
|
52314
52386
|
const calls = [];
|
|
@@ -52818,6 +52890,33 @@ function createAnthropicAdapter(requestBody, originalSystem) {
|
|
|
52818
52890
|
const model = requestBody.model ?? void 0;
|
|
52819
52891
|
let messageId;
|
|
52820
52892
|
let clientIndex = 0;
|
|
52893
|
+
let messageStartForwarded = false;
|
|
52894
|
+
const openBlocks = [];
|
|
52895
|
+
const removeOpenBlock = (index) => {
|
|
52896
|
+
const i = openBlocks.indexOf(index);
|
|
52897
|
+
if (i >= 0) openBlocks.splice(i, 1);
|
|
52898
|
+
};
|
|
52899
|
+
const buildSyntheticMessageStart = () => {
|
|
52900
|
+
const extra = {};
|
|
52901
|
+
if (model) extra.model = model;
|
|
52902
|
+
const msg = {
|
|
52903
|
+
id: messageId ?? `msg_acp_error_${Date.now()}`,
|
|
52904
|
+
type: "message",
|
|
52905
|
+
role: "assistant",
|
|
52906
|
+
content: [],
|
|
52907
|
+
stop_reason: null,
|
|
52908
|
+
stop_sequence: null,
|
|
52909
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
52910
|
+
...extra
|
|
52911
|
+
};
|
|
52912
|
+
return Buffer.from(
|
|
52913
|
+
`event: message_start
|
|
52914
|
+
data: ${JSON.stringify({ type: "message_start", message: msg })}
|
|
52915
|
+
|
|
52916
|
+
`,
|
|
52917
|
+
"utf8"
|
|
52918
|
+
);
|
|
52919
|
+
};
|
|
52821
52920
|
const buildTextBlock = (index, text) => Buffer.from(
|
|
52822
52921
|
`event: content_block_start
|
|
52823
52922
|
data: ${JSON.stringify({ type: "content_block_start", index, content_block: { type: "text", text: "" } })}
|
|
@@ -52901,6 +53000,7 @@ ${systemPrompt}` : systemPrompt;
|
|
|
52901
53000
|
if (typeof u2.input_tokens === "number") roundInput = u2.input_tokens;
|
|
52902
53001
|
if (typeof u2.cache_read_input_tokens === "number") roundCached = u2.cache_read_input_tokens;
|
|
52903
53002
|
if (round === 1) {
|
|
53003
|
+
messageStartForwarded = true;
|
|
52904
53004
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
52905
53005
|
}
|
|
52906
53006
|
} else if (type === "ping") {
|
|
@@ -52916,6 +53016,7 @@ ${systemPrompt}` : systemPrompt;
|
|
|
52916
53016
|
if (block.type === "thinking" || block.type === "redacted_thinking") thinkingIndexes.add(upstreamIndex);
|
|
52917
53017
|
const ci2 = clientIndex++;
|
|
52918
53018
|
indexMap.set(upstreamIndex, ci2);
|
|
53019
|
+
openBlocks.push(ci2);
|
|
52919
53020
|
yield { kind: "meta", chunk: remapIndexInEvent(eventStr, ci2), firstRoundOnly: round === 1 };
|
|
52920
53021
|
}
|
|
52921
53022
|
} else if (type === "content_block_delta") {
|
|
@@ -52965,10 +53066,12 @@ ${systemPrompt}` : systemPrompt;
|
|
|
52965
53066
|
};
|
|
52966
53067
|
} else if (thinkingIndexes.delete(upstreamIndex)) {
|
|
52967
53068
|
const ci2 = indexMap.get(upstreamIndex) ?? upstreamIndex;
|
|
53069
|
+
removeOpenBlock(ci2);
|
|
52968
53070
|
yield { kind: "meta", chunk: remapIndexInEvent(eventStr, ci2), firstRoundOnly: false };
|
|
52969
53071
|
yield { kind: "reasoning", delta: "", blockEnd: true };
|
|
52970
53072
|
} else {
|
|
52971
53073
|
const ci2 = indexMap.get(upstreamIndex) ?? upstreamIndex;
|
|
53074
|
+
removeOpenBlock(ci2);
|
|
52972
53075
|
if (lastTextIndex !== null) {
|
|
52973
53076
|
const tail = tagFilter.flush();
|
|
52974
53077
|
if (tail.length > 0) {
|
|
@@ -53060,10 +53163,22 @@ data: ${JSON.stringify({ type: "content_block_stop", index })}
|
|
|
53060
53163
|
);
|
|
53061
53164
|
},
|
|
53062
53165
|
emitError(message) {
|
|
53063
|
-
const
|
|
53166
|
+
const parts = [];
|
|
53167
|
+
if (!messageStartForwarded) {
|
|
53168
|
+
parts.push(buildSyntheticMessageStart());
|
|
53169
|
+
messageStartForwarded = true;
|
|
53170
|
+
}
|
|
53171
|
+
for (const index of openBlocks.splice(0)) {
|
|
53172
|
+
parts.push(Buffer.from(`event: content_block_stop
|
|
53173
|
+
data: ${JSON.stringify({ type: "content_block_stop", index })}
|
|
53174
|
+
|
|
53175
|
+
`, "utf8"));
|
|
53176
|
+
}
|
|
53177
|
+
parts.push(buildTextBlock(clientIndex++, `
|
|
53064
53178
|
[acp-proxy: ${message}]
|
|
53065
|
-
`);
|
|
53066
|
-
|
|
53179
|
+
`));
|
|
53180
|
+
parts.push(buildTerminal("end_turn", 0, 0, 0));
|
|
53181
|
+
return Buffer.concat(parts);
|
|
53067
53182
|
}
|
|
53068
53183
|
};
|
|
53069
53184
|
}
|
|
@@ -53254,6 +53369,86 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
|
|
|
53254
53369
|
return current;
|
|
53255
53370
|
}
|
|
53256
53371
|
|
|
53372
|
+
// src/fake-completion.ts
|
|
53373
|
+
var FAKE_COMPLETION_HINT = "[billion-context] Your last reply described a tool call as plain text instead of invoking it, so no tool actually ran. To act, invoke the tool through the proper tool-calling mechanism (emit a tool_use / tool_calls / function_call block). Do not write tool-call markup as text in your reply.";
|
|
53374
|
+
function maxFakeCompletionRetries() {
|
|
53375
|
+
const n = Number.parseInt(process.env.BILI_FAKE_COMPLETION_RETRIES ?? "0", 10);
|
|
53376
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
53377
|
+
}
|
|
53378
|
+
function fakeBufCap() {
|
|
53379
|
+
const n = Number.parseInt(process.env.BILI_FAKE_BUF_CAP ?? String(16 * 1024 * 1024), 10);
|
|
53380
|
+
return Number.isFinite(n) && n > 0 ? n : 16 * 1024 * 1024;
|
|
53381
|
+
}
|
|
53382
|
+
var ANTHROPIC_TOOL_BLOCK = /"type"\s*:\s*"tool_use"/;
|
|
53383
|
+
var OPENAI_TOOL_BLOCK = /"tool_calls"\s*:\s*\[\s*\{/;
|
|
53384
|
+
var RESPONSES_TOOL_BLOCK = /"type"\s*:\s*"function_call"/;
|
|
53385
|
+
function hasToolBlock(protocol, rawText) {
|
|
53386
|
+
switch (protocol) {
|
|
53387
|
+
case "anthropic":
|
|
53388
|
+
return ANTHROPIC_TOOL_BLOCK.test(rawText);
|
|
53389
|
+
case "openai":
|
|
53390
|
+
return OPENAI_TOOL_BLOCK.test(rawText);
|
|
53391
|
+
case "responses":
|
|
53392
|
+
return RESPONSES_TOOL_BLOCK.test(rawText);
|
|
53393
|
+
}
|
|
53394
|
+
}
|
|
53395
|
+
var TOOL_OPEN = /\x3c(?!\s*\/)(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b|\\u003c(?!\s*\/)(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b/i;
|
|
53396
|
+
var TOOL_CLOSE_GLOBAL = /\x3c\/(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b|\\u003c\/(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b/gi;
|
|
53397
|
+
function hasToolCallStructure(text) {
|
|
53398
|
+
if (!containsToolCallXmlFragment(text)) return false;
|
|
53399
|
+
if (TOOL_OPEN.test(text)) return true;
|
|
53400
|
+
const closes = /* @__PURE__ */ new Set();
|
|
53401
|
+
for (const m2 of text.matchAll(TOOL_CLOSE_GLOBAL)) {
|
|
53402
|
+
const name = m2[1] ?? m2[2];
|
|
53403
|
+
if (name) closes.add(name.toLowerCase());
|
|
53404
|
+
}
|
|
53405
|
+
return closes.size >= 2;
|
|
53406
|
+
}
|
|
53407
|
+
function isFakeCompletion(protocol, rawText) {
|
|
53408
|
+
return hasToolCallStructure(rawText) && !hasToolBlock(protocol, rawText);
|
|
53409
|
+
}
|
|
53410
|
+
function injectFakeCompletionHint(protocol, body) {
|
|
53411
|
+
const raw = typeof body === "string" ? body : body.toString("utf8");
|
|
53412
|
+
let obj;
|
|
53413
|
+
try {
|
|
53414
|
+
obj = JSON.parse(raw);
|
|
53415
|
+
} catch {
|
|
53416
|
+
return null;
|
|
53417
|
+
}
|
|
53418
|
+
if (protocol === "responses") {
|
|
53419
|
+
const input = obj.input;
|
|
53420
|
+
if (!Array.isArray(input)) return null;
|
|
53421
|
+
const arr2 = input;
|
|
53422
|
+
const last2 = arr2[arr2.length - 1];
|
|
53423
|
+
if (last2 && typeof last2 === "object" && last2.role === "user") {
|
|
53424
|
+
const c = last2.content;
|
|
53425
|
+
if (typeof c === "string") last2.content = `${c}
|
|
53426
|
+
|
|
53427
|
+
${FAKE_COMPLETION_HINT}`;
|
|
53428
|
+
else if (Array.isArray(c)) last2.content = [...c, { type: "input_text", text: FAKE_COMPLETION_HINT }];
|
|
53429
|
+
else last2.content = FAKE_COMPLETION_HINT;
|
|
53430
|
+
} else {
|
|
53431
|
+
arr2.push({ role: "user", content: [{ type: "input_text", text: FAKE_COMPLETION_HINT }] });
|
|
53432
|
+
}
|
|
53433
|
+
return JSON.stringify(obj);
|
|
53434
|
+
}
|
|
53435
|
+
const messages = obj.messages;
|
|
53436
|
+
if (!Array.isArray(messages)) return null;
|
|
53437
|
+
const arr = messages;
|
|
53438
|
+
const last = arr[arr.length - 1];
|
|
53439
|
+
if (last && typeof last === "object" && last.role === "user") {
|
|
53440
|
+
const c = last.content;
|
|
53441
|
+
if (typeof c === "string") last.content = `${c}
|
|
53442
|
+
|
|
53443
|
+
${FAKE_COMPLETION_HINT}`;
|
|
53444
|
+
else if (Array.isArray(c)) last.content = [...c, { type: "text", text: FAKE_COMPLETION_HINT }];
|
|
53445
|
+
else last.content = FAKE_COMPLETION_HINT;
|
|
53446
|
+
} else {
|
|
53447
|
+
arr.push({ role: "user", content: FAKE_COMPLETION_HINT });
|
|
53448
|
+
}
|
|
53449
|
+
return JSON.stringify(obj);
|
|
53450
|
+
}
|
|
53451
|
+
|
|
53257
53452
|
// src/stream-openai.ts
|
|
53258
53453
|
function rewriteOpenaiJsonResponse(body, ctx) {
|
|
53259
53454
|
if (!body || typeof body !== "object") return body;
|
|
@@ -54221,7 +54416,7 @@ function mergeUsageSample(acc, sample) {
|
|
|
54221
54416
|
if (sample.cachedTokens !== void 0) acc.cachedTokens = sample.cachedTokens;
|
|
54222
54417
|
if (sample.outputTokens !== void 0) acc.outputTokens = sample.outputTokens;
|
|
54223
54418
|
}
|
|
54224
|
-
async function pipePluginChatWithStrip(stream2, res,
|
|
54419
|
+
async function pipePluginChatWithStrip(stream2, res, protocol, session, log2) {
|
|
54225
54420
|
const reader = stream2.getReader();
|
|
54226
54421
|
const decoder = new TextDecoder("utf-8");
|
|
54227
54422
|
let buf = "";
|
|
@@ -54375,7 +54570,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
|
|
|
54375
54570
|
}
|
|
54376
54571
|
const rest = flushTails();
|
|
54377
54572
|
if (rest.length > 0 && !res.destroyed && !res.writableEnded) await write(rest);
|
|
54378
|
-
if (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0) {
|
|
54573
|
+
if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
|
|
54379
54574
|
applyUsageSample(session, acc, protocol);
|
|
54380
54575
|
markDirty(session);
|
|
54381
54576
|
}
|
|
@@ -54484,7 +54679,7 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
|
|
|
54484
54679
|
const rest = flushTail("");
|
|
54485
54680
|
if (rest.length > 0) await write(rest);
|
|
54486
54681
|
}
|
|
54487
|
-
if (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0) {
|
|
54682
|
+
if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
|
|
54488
54683
|
applyUsageSample(session, acc, "responses");
|
|
54489
54684
|
markDirty(session);
|
|
54490
54685
|
}
|
|
@@ -57511,7 +57706,7 @@ ${hdrText}
|
|
|
57511
57706
|
if (prepared.protocol === "responses") {
|
|
57512
57707
|
await pipePluginResponsesWithStrip(upstream.body, res, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
|
|
57513
57708
|
} else {
|
|
57514
|
-
await pipePluginChatWithStrip(upstream.body, res, prepared.
|
|
57709
|
+
await pipePluginChatWithStrip(upstream.body, res, prepared.protocol, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
|
|
57515
57710
|
}
|
|
57516
57711
|
} else {
|
|
57517
57712
|
await pipePluginJson(upstream.body, res, prepared.session, prepared.protocol);
|
|
@@ -57519,10 +57714,24 @@ ${hdrText}
|
|
|
57519
57714
|
clearUpstreamTimer();
|
|
57520
57715
|
return;
|
|
57521
57716
|
}
|
|
57717
|
+
let responseBody = upstream.body;
|
|
57718
|
+
if (prepared !== null && prepared.stream && maxFakeCompletionRetries() > 0) {
|
|
57719
|
+
const resolvedBuf = await resolveFakeCompletion(upstream.body, {
|
|
57720
|
+
protocol: prepared.protocol,
|
|
57721
|
+
body,
|
|
57722
|
+
upstreamUrl,
|
|
57723
|
+
reqHeaders: buildForwardHeaders(headers),
|
|
57724
|
+
proxyUrl,
|
|
57725
|
+
signal: clientAbort.signal,
|
|
57726
|
+
session: prepared.session,
|
|
57727
|
+
log: log2
|
|
57728
|
+
});
|
|
57729
|
+
responseBody = bufferToStream(resolvedBuf);
|
|
57730
|
+
}
|
|
57522
57731
|
const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
|
|
57523
57732
|
if (!useRewriter || prepared === null) {
|
|
57524
57733
|
if (prepared && prepared.resetAfterSuccess) {
|
|
57525
|
-
const [toClient, toObserve] =
|
|
57734
|
+
const [toClient, toObserve] = responseBody.tee();
|
|
57526
57735
|
const observed = observeResponsesTerminalState(toObserve, prepared.stream);
|
|
57527
57736
|
await pipeThrough(toClient, res);
|
|
57528
57737
|
clearUpstreamTimer();
|
|
@@ -57533,8 +57742,17 @@ ${hdrText}
|
|
|
57533
57742
|
} else {
|
|
57534
57743
|
log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
|
|
57535
57744
|
}
|
|
57745
|
+
} else if (prepared && prepared.stream && (upstream.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
57746
|
+
const p2 = prepared;
|
|
57747
|
+
const tagLog = (msg) => log2("info", `[${p2.session.id}] ${msg}`);
|
|
57748
|
+
if (p2.protocol === "responses") {
|
|
57749
|
+
await pipePluginResponsesWithStrip(responseBody, res, void 0, tagLog);
|
|
57750
|
+
} else {
|
|
57751
|
+
await pipePluginChatWithStrip(responseBody, res, p2.protocol, void 0, tagLog);
|
|
57752
|
+
}
|
|
57753
|
+
clearUpstreamTimer();
|
|
57536
57754
|
} else {
|
|
57537
|
-
await pipeThrough(
|
|
57755
|
+
await pipeThrough(responseBody, res);
|
|
57538
57756
|
clearUpstreamTimer();
|
|
57539
57757
|
}
|
|
57540
57758
|
return;
|
|
@@ -57548,10 +57766,10 @@ ${hdrText}
|
|
|
57548
57766
|
debug: opts.debug
|
|
57549
57767
|
};
|
|
57550
57768
|
if (prepared.stream) {
|
|
57551
|
-
let streamToRead =
|
|
57769
|
+
let streamToRead = responseBody;
|
|
57552
57770
|
let dumpRaw;
|
|
57553
57771
|
if (opts.dumpSse) {
|
|
57554
|
-
const [a, b2] =
|
|
57772
|
+
const [a, b2] = responseBody.tee();
|
|
57555
57773
|
streamToRead = a;
|
|
57556
57774
|
dumpRaw = dumpStreamToFile(b2, opts.dumpSse, `${Date.now()}-${safeSessionId(prepared.session.id)}-raw.sse`);
|
|
57557
57775
|
}
|
|
@@ -57677,6 +57895,58 @@ async function readStreamToBuffer(stream2, maxBytes = 1 << 20) {
|
|
|
57677
57895
|
}
|
|
57678
57896
|
return Buffer.concat(chunks);
|
|
57679
57897
|
}
|
|
57898
|
+
function bufferToStream(buf) {
|
|
57899
|
+
return new ReadableStream({
|
|
57900
|
+
start(controller) {
|
|
57901
|
+
controller.enqueue(new Uint8Array(buf));
|
|
57902
|
+
controller.close();
|
|
57903
|
+
}
|
|
57904
|
+
});
|
|
57905
|
+
}
|
|
57906
|
+
async function resolveFakeCompletion(stream2, opts) {
|
|
57907
|
+
let buffer = await readStreamToBuffer(stream2, fakeBufCap());
|
|
57908
|
+
const max = maxFakeCompletionRetries();
|
|
57909
|
+
const sid = opts.session.id;
|
|
57910
|
+
const priorStreak = opts.session.metadata.fakeCompletionStreak ?? 0;
|
|
57911
|
+
if (max > 0 && priorStreak < max && isFakeCompletion(opts.protocol, buffer.toString("utf8"))) {
|
|
57912
|
+
for (let attempt = 1; attempt <= max && !opts.signal.aborted; attempt++) {
|
|
57913
|
+
const hinted = injectFakeCompletionHint(opts.protocol, opts.body);
|
|
57914
|
+
if (hinted === null) break;
|
|
57915
|
+
opts.log("warn", `[${sid}] fake completion (tool-call XML, no tool block); retry ${attempt}/${max} with corrective hint`);
|
|
57916
|
+
let r;
|
|
57917
|
+
try {
|
|
57918
|
+
r = await fetchWithTimeout(
|
|
57919
|
+
opts.upstreamUrl,
|
|
57920
|
+
{
|
|
57921
|
+
method: "POST",
|
|
57922
|
+
headers: opts.reqHeaders,
|
|
57923
|
+
body: hinted,
|
|
57924
|
+
...opts.proxyUrl ? { dispatcher: proxyDispatcher(opts.proxyUrl) } : {}
|
|
57925
|
+
},
|
|
57926
|
+
void 0,
|
|
57927
|
+
opts.signal
|
|
57928
|
+
);
|
|
57929
|
+
} catch (e) {
|
|
57930
|
+
opts.log("warn", `[${sid}] fake-completion retry failed: ${String(e)}; presenting original`);
|
|
57931
|
+
break;
|
|
57932
|
+
}
|
|
57933
|
+
try {
|
|
57934
|
+
if (!r.response.ok || !r.response.body) {
|
|
57935
|
+
opts.log("warn", `[${sid}] fake-completion retry rejected (HTTP ${r.response.status}); presenting original`);
|
|
57936
|
+
break;
|
|
57937
|
+
}
|
|
57938
|
+
buffer = await readStreamToBuffer(r.response.body, fakeBufCap());
|
|
57939
|
+
} finally {
|
|
57940
|
+
r.clearTimer();
|
|
57941
|
+
}
|
|
57942
|
+
if (!isFakeCompletion(opts.protocol, buffer.toString("utf8"))) break;
|
|
57943
|
+
}
|
|
57944
|
+
}
|
|
57945
|
+
const stillFake = isFakeCompletion(opts.protocol, buffer.toString("utf8"));
|
|
57946
|
+
opts.session.metadata.fakeCompletionStreak = stillFake ? priorStreak + 1 : 0;
|
|
57947
|
+
markDirty(opts.session);
|
|
57948
|
+
return buffer;
|
|
57949
|
+
}
|
|
57680
57950
|
async function pipeThrough(stream2, res) {
|
|
57681
57951
|
const reader = stream2.getReader();
|
|
57682
57952
|
try {
|