billion-context 0.1.72 → 0.1.73-pr.474.289

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 CHANGED
@@ -53254,6 +53254,86 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
53254
53254
  return current;
53255
53255
  }
53256
53256
 
53257
+ // src/fake-completion.ts
53258
+ 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.";
53259
+ function maxFakeCompletionRetries() {
53260
+ const n = Number.parseInt(process.env.BILI_FAKE_COMPLETION_RETRIES ?? "0", 10);
53261
+ return Number.isFinite(n) && n >= 0 ? n : 0;
53262
+ }
53263
+ function fakeBufCap() {
53264
+ const n = Number.parseInt(process.env.BILI_FAKE_BUF_CAP ?? String(16 * 1024 * 1024), 10);
53265
+ return Number.isFinite(n) && n > 0 ? n : 16 * 1024 * 1024;
53266
+ }
53267
+ var ANTHROPIC_TOOL_BLOCK = /"type"\s*:\s*"tool_use"/;
53268
+ var OPENAI_TOOL_BLOCK = /"tool_calls"\s*:\s*\[\s*\{/;
53269
+ var RESPONSES_TOOL_BLOCK = /"type"\s*:\s*"function_call"/;
53270
+ function hasToolBlock(protocol, rawText) {
53271
+ switch (protocol) {
53272
+ case "anthropic":
53273
+ return ANTHROPIC_TOOL_BLOCK.test(rawText);
53274
+ case "openai":
53275
+ return OPENAI_TOOL_BLOCK.test(rawText);
53276
+ case "responses":
53277
+ return RESPONSES_TOOL_BLOCK.test(rawText);
53278
+ }
53279
+ }
53280
+ 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;
53281
+ 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;
53282
+ function hasToolCallStructure(text) {
53283
+ if (!containsToolCallXmlFragment(text)) return false;
53284
+ if (TOOL_OPEN.test(text)) return true;
53285
+ const closes = /* @__PURE__ */ new Set();
53286
+ for (const m2 of text.matchAll(TOOL_CLOSE_GLOBAL)) {
53287
+ const name = m2[1] ?? m2[2];
53288
+ if (name) closes.add(name.toLowerCase());
53289
+ }
53290
+ return closes.size >= 2;
53291
+ }
53292
+ function isFakeCompletion(protocol, rawText) {
53293
+ return hasToolCallStructure(rawText) && !hasToolBlock(protocol, rawText);
53294
+ }
53295
+ function injectFakeCompletionHint(protocol, body) {
53296
+ const raw = typeof body === "string" ? body : body.toString("utf8");
53297
+ let obj;
53298
+ try {
53299
+ obj = JSON.parse(raw);
53300
+ } catch {
53301
+ return null;
53302
+ }
53303
+ if (protocol === "responses") {
53304
+ const input = obj.input;
53305
+ if (!Array.isArray(input)) return null;
53306
+ const arr2 = input;
53307
+ const last2 = arr2[arr2.length - 1];
53308
+ if (last2 && typeof last2 === "object" && last2.role === "user") {
53309
+ const c = last2.content;
53310
+ if (typeof c === "string") last2.content = `${c}
53311
+
53312
+ ${FAKE_COMPLETION_HINT}`;
53313
+ else if (Array.isArray(c)) last2.content = [...c, { type: "input_text", text: FAKE_COMPLETION_HINT }];
53314
+ else last2.content = FAKE_COMPLETION_HINT;
53315
+ } else {
53316
+ arr2.push({ role: "user", content: [{ type: "input_text", text: FAKE_COMPLETION_HINT }] });
53317
+ }
53318
+ return JSON.stringify(obj);
53319
+ }
53320
+ const messages = obj.messages;
53321
+ if (!Array.isArray(messages)) return null;
53322
+ const arr = messages;
53323
+ const last = arr[arr.length - 1];
53324
+ if (last && typeof last === "object" && last.role === "user") {
53325
+ const c = last.content;
53326
+ if (typeof c === "string") last.content = `${c}
53327
+
53328
+ ${FAKE_COMPLETION_HINT}`;
53329
+ else if (Array.isArray(c)) last.content = [...c, { type: "text", text: FAKE_COMPLETION_HINT }];
53330
+ else last.content = FAKE_COMPLETION_HINT;
53331
+ } else {
53332
+ arr.push({ role: "user", content: FAKE_COMPLETION_HINT });
53333
+ }
53334
+ return JSON.stringify(obj);
53335
+ }
53336
+
53257
53337
  // src/stream-openai.ts
53258
53338
  function rewriteOpenaiJsonResponse(body, ctx) {
53259
53339
  if (!body || typeof body !== "object") return body;
@@ -54221,7 +54301,7 @@ function mergeUsageSample(acc, sample) {
54221
54301
  if (sample.cachedTokens !== void 0) acc.cachedTokens = sample.cachedTokens;
54222
54302
  if (sample.outputTokens !== void 0) acc.outputTokens = sample.outputTokens;
54223
54303
  }
54224
- async function pipePluginChatWithStrip(stream2, res, session, protocol, log2) {
54304
+ async function pipePluginChatWithStrip(stream2, res, protocol, session, log2) {
54225
54305
  const reader = stream2.getReader();
54226
54306
  const decoder = new TextDecoder("utf-8");
54227
54307
  let buf = "";
@@ -54375,7 +54455,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54375
54455
  }
54376
54456
  const rest = flushTails();
54377
54457
  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) {
54458
+ if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
54379
54459
  applyUsageSample(session, acc, protocol);
54380
54460
  markDirty(session);
54381
54461
  }
@@ -54484,7 +54564,7 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
54484
54564
  const rest = flushTail("");
54485
54565
  if (rest.length > 0) await write(rest);
54486
54566
  }
54487
- if (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0) {
54567
+ if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
54488
54568
  applyUsageSample(session, acc, "responses");
54489
54569
  markDirty(session);
54490
54570
  }
@@ -57511,7 +57591,7 @@ ${hdrText}
57511
57591
  if (prepared.protocol === "responses") {
57512
57592
  await pipePluginResponsesWithStrip(upstream.body, res, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57513
57593
  } else {
57514
- await pipePluginChatWithStrip(upstream.body, res, prepared.session, prepared.protocol, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57594
+ await pipePluginChatWithStrip(upstream.body, res, prepared.protocol, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57515
57595
  }
57516
57596
  } else {
57517
57597
  await pipePluginJson(upstream.body, res, prepared.session, prepared.protocol);
@@ -57519,10 +57599,24 @@ ${hdrText}
57519
57599
  clearUpstreamTimer();
57520
57600
  return;
57521
57601
  }
57602
+ let responseBody = upstream.body;
57603
+ if (prepared !== null && prepared.stream && maxFakeCompletionRetries() > 0) {
57604
+ const resolvedBuf = await resolveFakeCompletion(upstream.body, {
57605
+ protocol: prepared.protocol,
57606
+ body,
57607
+ upstreamUrl,
57608
+ reqHeaders: buildForwardHeaders(headers),
57609
+ proxyUrl,
57610
+ signal: clientAbort.signal,
57611
+ session: prepared.session,
57612
+ log: log2
57613
+ });
57614
+ responseBody = bufferToStream(resolvedBuf);
57615
+ }
57522
57616
  const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
57523
57617
  if (!useRewriter || prepared === null) {
57524
57618
  if (prepared && prepared.resetAfterSuccess) {
57525
- const [toClient, toObserve] = upstream.body.tee();
57619
+ const [toClient, toObserve] = responseBody.tee();
57526
57620
  const observed = observeResponsesTerminalState(toObserve, prepared.stream);
57527
57621
  await pipeThrough(toClient, res);
57528
57622
  clearUpstreamTimer();
@@ -57533,8 +57627,17 @@ ${hdrText}
57533
57627
  } else {
57534
57628
  log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
57535
57629
  }
57630
+ } else if (prepared && prepared.stream && (upstream.headers.get("content-type") ?? "").includes("text/event-stream")) {
57631
+ const p2 = prepared;
57632
+ const tagLog = (msg) => log2("info", `[${p2.session.id}] ${msg}`);
57633
+ if (p2.protocol === "responses") {
57634
+ await pipePluginResponsesWithStrip(responseBody, res, void 0, tagLog);
57635
+ } else {
57636
+ await pipePluginChatWithStrip(responseBody, res, p2.protocol, void 0, tagLog);
57637
+ }
57638
+ clearUpstreamTimer();
57536
57639
  } else {
57537
- await pipeThrough(upstream.body, res);
57640
+ await pipeThrough(responseBody, res);
57538
57641
  clearUpstreamTimer();
57539
57642
  }
57540
57643
  return;
@@ -57548,10 +57651,10 @@ ${hdrText}
57548
57651
  debug: opts.debug
57549
57652
  };
57550
57653
  if (prepared.stream) {
57551
- let streamToRead = upstream.body;
57654
+ let streamToRead = responseBody;
57552
57655
  let dumpRaw;
57553
57656
  if (opts.dumpSse) {
57554
- const [a, b2] = upstream.body.tee();
57657
+ const [a, b2] = responseBody.tee();
57555
57658
  streamToRead = a;
57556
57659
  dumpRaw = dumpStreamToFile(b2, opts.dumpSse, `${Date.now()}-${safeSessionId(prepared.session.id)}-raw.sse`);
57557
57660
  }
@@ -57677,6 +57780,58 @@ async function readStreamToBuffer(stream2, maxBytes = 1 << 20) {
57677
57780
  }
57678
57781
  return Buffer.concat(chunks);
57679
57782
  }
57783
+ function bufferToStream(buf) {
57784
+ return new ReadableStream({
57785
+ start(controller) {
57786
+ controller.enqueue(new Uint8Array(buf));
57787
+ controller.close();
57788
+ }
57789
+ });
57790
+ }
57791
+ async function resolveFakeCompletion(stream2, opts) {
57792
+ let buffer = await readStreamToBuffer(stream2, fakeBufCap());
57793
+ const max = maxFakeCompletionRetries();
57794
+ const sid = opts.session.id;
57795
+ const priorStreak = opts.session.metadata.fakeCompletionStreak ?? 0;
57796
+ if (max > 0 && priorStreak < max && isFakeCompletion(opts.protocol, buffer.toString("utf8"))) {
57797
+ for (let attempt = 1; attempt <= max && !opts.signal.aborted; attempt++) {
57798
+ const hinted = injectFakeCompletionHint(opts.protocol, opts.body);
57799
+ if (hinted === null) break;
57800
+ opts.log("warn", `[${sid}] fake completion (tool-call XML, no tool block); retry ${attempt}/${max} with corrective hint`);
57801
+ let r;
57802
+ try {
57803
+ r = await fetchWithTimeout(
57804
+ opts.upstreamUrl,
57805
+ {
57806
+ method: "POST",
57807
+ headers: opts.reqHeaders,
57808
+ body: hinted,
57809
+ ...opts.proxyUrl ? { dispatcher: proxyDispatcher(opts.proxyUrl) } : {}
57810
+ },
57811
+ void 0,
57812
+ opts.signal
57813
+ );
57814
+ } catch (e) {
57815
+ opts.log("warn", `[${sid}] fake-completion retry failed: ${String(e)}; presenting original`);
57816
+ break;
57817
+ }
57818
+ try {
57819
+ if (!r.response.ok || !r.response.body) {
57820
+ opts.log("warn", `[${sid}] fake-completion retry rejected (HTTP ${r.response.status}); presenting original`);
57821
+ break;
57822
+ }
57823
+ buffer = await readStreamToBuffer(r.response.body, fakeBufCap());
57824
+ } finally {
57825
+ r.clearTimer();
57826
+ }
57827
+ if (!isFakeCompletion(opts.protocol, buffer.toString("utf8"))) break;
57828
+ }
57829
+ }
57830
+ const stillFake = isFakeCompletion(opts.protocol, buffer.toString("utf8"));
57831
+ opts.session.metadata.fakeCompletionStreak = stillFake ? priorStreak + 1 : 0;
57832
+ markDirty(opts.session);
57833
+ return buffer;
57834
+ }
57680
57835
  async function pipeThrough(stream2, res) {
57681
57836
  const reader = stream2.getReader();
57682
57837
  try {