billion-context 0.1.71 → 0.1.72-pr.378.288

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
@@ -50241,6 +50241,9 @@ var RENDER_TAG_DETECT = /\x3c\/?acp(?=[\s>])|\\u003c\/?acp(?=[\s>\\])/;
50241
50241
  function containsRenderTagText(s3) {
50242
50242
  return RENDER_TAG_DETECT.test(s3);
50243
50243
  }
50244
+ function mayStartRenderTag(s3) {
50245
+ return RENDER_TAG_DETECT.test(s3) || PARTIAL_TAIL.test(s3);
50246
+ }
50244
50247
  var TOOL_CALL_XML = /\x3c\/?(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b[^<>]*\x3e|\\u003c\/?(?:antml:)?(invoke|tool_calls|tool_call|parameter|parameters)\b|\x3c\/?antml:[a-z_]+/i;
50245
50248
  function containsToolCallXmlFragment(s3) {
50246
50249
  return TOOL_CALL_XML.test(s3);
@@ -53251,6 +53254,86 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
53251
53254
  return current;
53252
53255
  }
53253
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
+
53254
53337
  // src/stream-openai.ts
53255
53338
  function rewriteOpenaiJsonResponse(body, ctx) {
53256
53339
  if (!body || typeof body !== "object") return body;
@@ -54218,7 +54301,7 @@ function mergeUsageSample(acc, sample) {
54218
54301
  if (sample.cachedTokens !== void 0) acc.cachedTokens = sample.cachedTokens;
54219
54302
  if (sample.outputTokens !== void 0) acc.outputTokens = sample.outputTokens;
54220
54303
  }
54221
- async function pipePluginChatWithStrip(stream2, res, session, protocol, log2) {
54304
+ async function pipePluginChatWithStrip(stream2, res, protocol, session, log2) {
54222
54305
  const reader = stream2.getReader();
54223
54306
  const decoder = new TextDecoder("utf-8");
54224
54307
  let buf = "";
@@ -54282,6 +54365,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54282
54365
  }
54283
54366
  let rebuilt = null;
54284
54367
  let droppedText = false;
54368
+ let keptText = false;
54285
54369
  let hadText = false;
54286
54370
  for (let ci2 = 0; ci2 < choices.length; ci2++) {
54287
54371
  const ch = choices[ci2];
@@ -54292,10 +54376,14 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54292
54376
  const v2 = dd[field];
54293
54377
  if (typeof v2 !== "string") continue;
54294
54378
  hadText = true;
54295
- if (!containsRenderTagText(v2) && !anyPending()) continue;
54379
+ if (!mayStartRenderTag(v2) && !anyPending()) {
54380
+ if (v2.length > 0) keptText = true;
54381
+ continue;
54382
+ }
54296
54383
  const index = typeof ch?.["index"] === "number" ? ch["index"] : ci2;
54297
54384
  const [clean, changed] = pushField(field, index, v2);
54298
54385
  if (clean.length === 0) droppedText = true;
54386
+ else keptText = true;
54299
54387
  if (changed) {
54300
54388
  if (!rebuilt) {
54301
54389
  rebuilt = { ...ev, choices: choices.map((c) => ({ ...c, delta: { ...c["delta"] } })) };
@@ -54305,7 +54393,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54305
54393
  }
54306
54394
  }
54307
54395
  if (rebuilt) {
54308
- if (droppedText && !hadTextOtherThanTextFields(rebuilt["choices"])) {
54396
+ if (droppedText && !keptText && !hadTextOtherThanTextFields(rebuilt["choices"])) {
54309
54397
  return "";
54310
54398
  }
54311
54399
  return rebuildEvent(rawEvent, rebuilt);
@@ -54324,7 +54412,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54324
54412
  return rawEvent + "\n\n";
54325
54413
  }
54326
54414
  const raw = d[field];
54327
- if (!containsRenderTagText(raw) && !anyPending()) {
54415
+ if (!mayStartRenderTag(raw) && !anyPending()) {
54328
54416
  return rawEvent + "\n\n";
54329
54417
  }
54330
54418
  const [clean, changed] = pushField(field, index, raw);
@@ -54367,7 +54455,7 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
54367
54455
  }
54368
54456
  const rest = flushTails();
54369
54457
  if (rest.length > 0 && !res.destroyed && !res.writableEnded) await write(rest);
54370
- 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)) {
54371
54459
  applyUsageSample(session, acc, protocol);
54372
54460
  markDirty(session);
54373
54461
  }
@@ -54453,7 +54541,7 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
54453
54541
  await write(rawEvent + "\n\n");
54454
54542
  continue;
54455
54543
  }
54456
- if (!containsRenderTagText(delta) && !tagFilter.pending()) {
54544
+ if (!mayStartRenderTag(delta) && !tagFilter.pending()) {
54457
54545
  await write(rawEvent + "\n\n");
54458
54546
  continue;
54459
54547
  }
@@ -54476,7 +54564,7 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
54476
54564
  const rest = flushTail("");
54477
54565
  if (rest.length > 0) await write(rest);
54478
54566
  }
54479
- 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)) {
54480
54568
  applyUsageSample(session, acc, "responses");
54481
54569
  markDirty(session);
54482
54570
  }
@@ -57503,7 +57591,7 @@ ${hdrText}
57503
57591
  if (prepared.protocol === "responses") {
57504
57592
  await pipePluginResponsesWithStrip(upstream.body, res, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57505
57593
  } else {
57506
- 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}`));
57507
57595
  }
57508
57596
  } else {
57509
57597
  await pipePluginJson(upstream.body, res, prepared.session, prepared.protocol);
@@ -57511,10 +57599,24 @@ ${hdrText}
57511
57599
  clearUpstreamTimer();
57512
57600
  return;
57513
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
+ }
57514
57616
  const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
57515
57617
  if (!useRewriter || prepared === null) {
57516
57618
  if (prepared && prepared.resetAfterSuccess) {
57517
- const [toClient, toObserve] = upstream.body.tee();
57619
+ const [toClient, toObserve] = responseBody.tee();
57518
57620
  const observed = observeResponsesTerminalState(toObserve, prepared.stream);
57519
57621
  await pipeThrough(toClient, res);
57520
57622
  clearUpstreamTimer();
@@ -57525,8 +57627,17 @@ ${hdrText}
57525
57627
  } else {
57526
57628
  log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
57527
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();
57528
57639
  } else {
57529
- await pipeThrough(upstream.body, res);
57640
+ await pipeThrough(responseBody, res);
57530
57641
  clearUpstreamTimer();
57531
57642
  }
57532
57643
  return;
@@ -57540,10 +57651,10 @@ ${hdrText}
57540
57651
  debug: opts.debug
57541
57652
  };
57542
57653
  if (prepared.stream) {
57543
- let streamToRead = upstream.body;
57654
+ let streamToRead = responseBody;
57544
57655
  let dumpRaw;
57545
57656
  if (opts.dumpSse) {
57546
- const [a, b2] = upstream.body.tee();
57657
+ const [a, b2] = responseBody.tee();
57547
57658
  streamToRead = a;
57548
57659
  dumpRaw = dumpStreamToFile(b2, opts.dumpSse, `${Date.now()}-${safeSessionId(prepared.session.id)}-raw.sse`);
57549
57660
  }
@@ -57669,6 +57780,58 @@ async function readStreamToBuffer(stream2, maxBytes = 1 << 20) {
57669
57780
  }
57670
57781
  return Buffer.concat(chunks);
57671
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
+ }
57672
57835
  async function pipeThrough(stream2, res) {
57673
57836
  const reader = stream2.getReader();
57674
57837
  try {