billion-context 0.1.70 → 0.1.71-pr.378.283

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
@@ -50369,6 +50369,50 @@ function stripItemContent(it2) {
50369
50369
  }
50370
50370
  return it2;
50371
50371
  }
50372
+ function stripIfString(v2) {
50373
+ return typeof v2 === "string" ? stripAcpTags(v2) : v2;
50374
+ }
50375
+ function stripOpenaiChatText(obj) {
50376
+ if (!obj || typeof obj !== "object") return obj;
50377
+ const o = obj;
50378
+ if (!Array.isArray(o["choices"])) return obj;
50379
+ o["choices"] = o["choices"].map((c) => {
50380
+ if (!c || typeof c !== "object") return c;
50381
+ const ch = c;
50382
+ for (const holder of ["delta", "message"]) {
50383
+ const h = ch[holder];
50384
+ if (h && typeof h === "object") {
50385
+ const hh = { ...h };
50386
+ hh["content"] = stripIfString(hh["content"]);
50387
+ hh["reasoning_content"] = stripIfString(hh["reasoning_content"]);
50388
+ hh["reasoning"] = stripIfString(hh["reasoning"]);
50389
+ ch[holder] = hh;
50390
+ }
50391
+ }
50392
+ return ch;
50393
+ });
50394
+ return obj;
50395
+ }
50396
+ function stripAnthropicText(obj) {
50397
+ if (!obj || typeof obj !== "object") return obj;
50398
+ const o = obj;
50399
+ const d = o["delta"];
50400
+ if (d && typeof d === "object") {
50401
+ const dd = { ...d };
50402
+ dd["text"] = stripIfString(dd["text"]);
50403
+ dd["thinking"] = stripIfString(dd["thinking"]);
50404
+ o["delta"] = dd;
50405
+ }
50406
+ if (Array.isArray(o["content"])) {
50407
+ o["content"] = o["content"].map((c) => {
50408
+ if (!c || typeof c !== "object") return c;
50409
+ const cc = c;
50410
+ if (typeof cc["text"] !== "string" && typeof cc["thinking"] !== "string") return c;
50411
+ return { ...cc, text: stripIfString(cc["text"]), thinking: stripIfString(cc["thinking"]) };
50412
+ });
50413
+ }
50414
+ return obj;
50415
+ }
50372
50416
  function stripResponsesText(obj) {
50373
50417
  if (!obj || typeof obj !== "object") return obj;
50374
50418
  const o = obj;
@@ -53207,6 +53251,86 @@ async function compressLoopResponsesJson(initialResponse, ctx, requestBody, requ
53207
53251
  return current;
53208
53252
  }
53209
53253
 
53254
+ // src/fake-completion.ts
53255
+ 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.";
53256
+ function maxFakeCompletionRetries() {
53257
+ const n = Number.parseInt(process.env.BILI_FAKE_COMPLETION_RETRIES ?? "0", 10);
53258
+ return Number.isFinite(n) && n >= 0 ? n : 0;
53259
+ }
53260
+ function fakeBufCap() {
53261
+ const n = Number.parseInt(process.env.BILI_FAKE_BUF_CAP ?? String(16 * 1024 * 1024), 10);
53262
+ return Number.isFinite(n) && n > 0 ? n : 16 * 1024 * 1024;
53263
+ }
53264
+ var ANTHROPIC_TOOL_BLOCK = /"type"\s*:\s*"tool_use"/;
53265
+ var OPENAI_TOOL_BLOCK = /"tool_calls"\s*:\s*\[\s*\{/;
53266
+ var RESPONSES_TOOL_BLOCK = /"type"\s*:\s*"function_call"/;
53267
+ function hasToolBlock(protocol, rawText) {
53268
+ switch (protocol) {
53269
+ case "anthropic":
53270
+ return ANTHROPIC_TOOL_BLOCK.test(rawText);
53271
+ case "openai":
53272
+ return OPENAI_TOOL_BLOCK.test(rawText);
53273
+ case "responses":
53274
+ return RESPONSES_TOOL_BLOCK.test(rawText);
53275
+ }
53276
+ }
53277
+ 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;
53278
+ 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;
53279
+ function hasToolCallStructure(text) {
53280
+ if (!containsToolCallXmlFragment(text)) return false;
53281
+ if (TOOL_OPEN.test(text)) return true;
53282
+ const closes = /* @__PURE__ */ new Set();
53283
+ for (const m2 of text.matchAll(TOOL_CLOSE_GLOBAL)) {
53284
+ const name = m2[1] ?? m2[2];
53285
+ if (name) closes.add(name.toLowerCase());
53286
+ }
53287
+ return closes.size >= 2;
53288
+ }
53289
+ function isFakeCompletion(protocol, rawText) {
53290
+ return hasToolCallStructure(rawText) && !hasToolBlock(protocol, rawText);
53291
+ }
53292
+ function injectFakeCompletionHint(protocol, body) {
53293
+ const raw = typeof body === "string" ? body : body.toString("utf8");
53294
+ let obj;
53295
+ try {
53296
+ obj = JSON.parse(raw);
53297
+ } catch {
53298
+ return null;
53299
+ }
53300
+ if (protocol === "responses") {
53301
+ const input = obj.input;
53302
+ if (!Array.isArray(input)) return null;
53303
+ const arr2 = input;
53304
+ const last2 = arr2[arr2.length - 1];
53305
+ if (last2 && typeof last2 === "object" && last2.role === "user") {
53306
+ const c = last2.content;
53307
+ if (typeof c === "string") last2.content = `${c}
53308
+
53309
+ ${FAKE_COMPLETION_HINT}`;
53310
+ else if (Array.isArray(c)) last2.content = [...c, { type: "input_text", text: FAKE_COMPLETION_HINT }];
53311
+ else last2.content = FAKE_COMPLETION_HINT;
53312
+ } else {
53313
+ arr2.push({ role: "user", content: [{ type: "input_text", text: FAKE_COMPLETION_HINT }] });
53314
+ }
53315
+ return JSON.stringify(obj);
53316
+ }
53317
+ const messages = obj.messages;
53318
+ if (!Array.isArray(messages)) return null;
53319
+ const arr = messages;
53320
+ const last = arr[arr.length - 1];
53321
+ if (last && typeof last === "object" && last.role === "user") {
53322
+ const c = last.content;
53323
+ if (typeof c === "string") last.content = `${c}
53324
+
53325
+ ${FAKE_COMPLETION_HINT}`;
53326
+ else if (Array.isArray(c)) last.content = [...c, { type: "text", text: FAKE_COMPLETION_HINT }];
53327
+ else last.content = FAKE_COMPLETION_HINT;
53328
+ } else {
53329
+ arr.push({ role: "user", content: FAKE_COMPLETION_HINT });
53330
+ }
53331
+ return JSON.stringify(obj);
53332
+ }
53333
+
53210
53334
  // src/stream-openai.ts
53211
53335
  function rewriteOpenaiJsonResponse(body, ctx) {
53212
53336
  if (!body || typeof body !== "object") return body;
@@ -54174,19 +54298,125 @@ function mergeUsageSample(acc, sample) {
54174
54298
  if (sample.cachedTokens !== void 0) acc.cachedTokens = sample.cachedTokens;
54175
54299
  if (sample.outputTokens !== void 0) acc.outputTokens = sample.outputTokens;
54176
54300
  }
54177
- async function pipeThroughWithUsage(stream2, res, session, protocol) {
54301
+ async function pipePluginChatWithStrip(stream2, res, session, protocol, log2) {
54178
54302
  const reader = stream2.getReader();
54179
54303
  const decoder = new TextDecoder("utf-8");
54180
54304
  let buf = "";
54181
54305
  const acc = {};
54306
+ const onDrop = (snippet) => {
54307
+ log("warn", `[tag-echo] stripped model-emitted render tag (plugin passthrough): ${snippet.slice(0, 80).replace(/\n/g, " ")}`);
54308
+ log2?.(`[tag-echo] stripped model-emitted render tag from plugin passthrough text`);
54309
+ };
54310
+ const streams = /* @__PURE__ */ new Map();
54311
+ const filterFor = (field, index) => {
54312
+ const key = `${field}:${index}`;
54313
+ let s3 = streams.get(key);
54314
+ if (!s3) {
54315
+ s3 = { filter: createTagEchoFilter(onDrop), field, index };
54316
+ streams.set(key, s3);
54317
+ }
54318
+ return s3;
54319
+ };
54320
+ const anyPending = () => {
54321
+ for (const s3 of streams.values()) if (s3.filter.pending()) return true;
54322
+ return false;
54323
+ };
54324
+ let lastChunkMeta = {};
54325
+ const syntheticTail = (field, index, tail) => {
54326
+ if (protocol === "anthropic") {
54327
+ const deltaType = field === "text" ? "text_delta" : "thinking_delta";
54328
+ return `event: content_block_delta
54329
+ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: deltaType, [field]: tail } })}
54330
+
54331
+ `;
54332
+ }
54333
+ return `data: ${JSON.stringify({ ...lastChunkMeta, object: "chat.completion.chunk", choices: [{ index, delta: { [field]: tail } }] })}
54334
+
54335
+ `;
54336
+ };
54337
+ const flushTails = () => {
54338
+ let out = "";
54339
+ for (const s3 of streams.values()) {
54340
+ const tail = s3.filter.flush();
54341
+ if (tail.length > 0) out += syntheticTail(s3.field, s3.index, tail);
54342
+ }
54343
+ return out;
54344
+ };
54345
+ const write = (s3) => {
54346
+ if (!res.write(Buffer.from(s3, "utf8"))) {
54347
+ return new Promise((r) => res.once("drain", () => r()));
54348
+ }
54349
+ };
54350
+ const pushField = (field, index, text) => {
54351
+ const s3 = filterFor(field, index);
54352
+ const clean = s3.filter.push(text);
54353
+ return [clean, clean !== text];
54354
+ };
54355
+ const processOpenai = (ev, rawEvent) => {
54356
+ if (typeof ev["id"] === "string" || typeof ev["model"] === "string") {
54357
+ lastChunkMeta = { id: ev["id"], created: ev["created"], model: ev["model"] };
54358
+ }
54359
+ const choices = ev["choices"];
54360
+ if (!Array.isArray(choices)) {
54361
+ return anyPending() ? flushTails() + rawEvent + "\n\n" : rawEvent + "\n\n";
54362
+ }
54363
+ let rebuilt = null;
54364
+ let droppedText = false;
54365
+ let hadText = false;
54366
+ for (let ci2 = 0; ci2 < choices.length; ci2++) {
54367
+ const ch = choices[ci2];
54368
+ const d = ch?.["delta"];
54369
+ if (!d || typeof d !== "object") continue;
54370
+ const dd = d;
54371
+ for (const field of ["content", "reasoning_content", "reasoning"]) {
54372
+ const v2 = dd[field];
54373
+ if (typeof v2 !== "string") continue;
54374
+ hadText = true;
54375
+ if (!containsRenderTagText(v2) && !anyPending()) continue;
54376
+ const index = typeof ch?.["index"] === "number" ? ch["index"] : ci2;
54377
+ const [clean, changed] = pushField(field, index, v2);
54378
+ if (clean.length === 0) droppedText = true;
54379
+ if (changed) {
54380
+ if (!rebuilt) {
54381
+ rebuilt = { ...ev, choices: choices.map((c) => ({ ...c, delta: { ...c["delta"] } })) };
54382
+ }
54383
+ rebuilt["choices"][ci2]["delta"] = { ...rebuilt["choices"][ci2]["delta"], [field]: clean };
54384
+ }
54385
+ }
54386
+ }
54387
+ if (rebuilt) {
54388
+ if (droppedText && !hadTextOtherThanTextFields(rebuilt["choices"])) {
54389
+ return "";
54390
+ }
54391
+ return rebuildEvent(rawEvent, rebuilt);
54392
+ }
54393
+ if (!hadText && anyPending()) return flushTails() + rawEvent + "\n\n";
54394
+ return rawEvent + "\n\n";
54395
+ };
54396
+ const processAnthropic = (ev, rawEvent) => {
54397
+ if (ev["type"] !== "content_block_delta") {
54398
+ return anyPending() ? flushTails() + rawEvent + "\n\n" : rawEvent + "\n\n";
54399
+ }
54400
+ const d = ev["delta"];
54401
+ const index = typeof ev["index"] === "number" ? ev["index"] : 0;
54402
+ const field = d?.["type"] === "thinking_delta" ? "thinking" : d?.["type"] === "text_delta" ? "text" : null;
54403
+ if (field === null || typeof d?.[field] !== "string") {
54404
+ return rawEvent + "\n\n";
54405
+ }
54406
+ const raw = d[field];
54407
+ if (!containsRenderTagText(raw) && !anyPending()) {
54408
+ return rawEvent + "\n\n";
54409
+ }
54410
+ const [clean, changed] = pushField(field, index, raw);
54411
+ if (!changed) return rawEvent + "\n\n";
54412
+ if (clean.length === 0 && Object.keys(d ?? {}).length <= 2) return "";
54413
+ return rebuildEvent(rawEvent, { ...ev, delta: { ...d, [field]: clean } });
54414
+ };
54182
54415
  try {
54183
54416
  for (; ; ) {
54184
54417
  const { done, value } = await reader.read();
54185
54418
  if (done) break;
54186
54419
  if (value && value.length > 0) {
54187
- if (!res.write(Buffer.from(value))) {
54188
- await new Promise((r) => res.once("drain", () => r()));
54189
- }
54190
54420
  buf = normalizeSseLineEndings(buf + decoder.decode(value, { stream: true }));
54191
54421
  let idx;
54192
54422
  while ((idx = buf.indexOf("\n\n")) !== -1) {
@@ -54195,17 +54425,28 @@ async function pipeThroughWithUsage(stream2, res, session, protocol) {
54195
54425
  const dataLines = rawEvent.split("\n").filter((l) => l.startsWith("data:"));
54196
54426
  if (dataLines.length === 0) continue;
54197
54427
  const jsonStr = dataLines.map((l) => l.slice(5).replace(/^ /, "")).join("\n").trim();
54198
- if (!jsonStr || jsonStr === "[DONE]") continue;
54428
+ if (!jsonStr) continue;
54429
+ if (jsonStr === "[DONE]") {
54430
+ await write(flushTails() + rawEvent + "\n\n");
54431
+ continue;
54432
+ }
54433
+ let ev;
54199
54434
  try {
54200
- const ev = JSON.parse(jsonStr);
54201
- const sample = usageFromSseEvent(ev);
54202
- if (sample) mergeUsageSample(acc, sample);
54435
+ ev = JSON.parse(jsonStr);
54203
54436
  } catch {
54437
+ await write(rawEvent + "\n\n");
54438
+ continue;
54204
54439
  }
54440
+ const sample = usageFromSseEvent(ev);
54441
+ if (sample) mergeUsageSample(acc, sample);
54442
+ const out = protocol === "anthropic" ? processAnthropic(ev, rawEvent) : processOpenai(ev, rawEvent);
54443
+ if (out.length > 0) await write(out);
54205
54444
  }
54206
54445
  }
54207
54446
  if (res.destroyed || res.writableEnded) break;
54208
54447
  }
54448
+ const rest = flushTails();
54449
+ if (rest.length > 0 && !res.destroyed && !res.writableEnded) await write(rest);
54209
54450
  if (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0) {
54210
54451
  applyUsageSample(session, acc, protocol);
54211
54452
  markDirty(session);
@@ -54215,6 +54456,20 @@ async function pipeThroughWithUsage(stream2, res, session, protocol) {
54215
54456
  res.end();
54216
54457
  }
54217
54458
  }
54459
+ function hadTextOtherThanTextFields(choices) {
54460
+ if (!Array.isArray(choices)) return true;
54461
+ for (const c of choices) {
54462
+ if (!c || typeof c !== "object") continue;
54463
+ const ch = c;
54464
+ if (typeof ch["finish_reason"] === "string") return true;
54465
+ const d = ch["delta"];
54466
+ if (!d) continue;
54467
+ for (const k2 of Object.keys(d)) {
54468
+ if (k2 !== "content" && k2 !== "reasoning_content" && k2 !== "reasoning") return true;
54469
+ }
54470
+ }
54471
+ return false;
54472
+ }
54218
54473
  async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
54219
54474
  const reader = stream2.getReader();
54220
54475
  const decoder = new TextDecoder("utf-8");
@@ -54353,13 +54608,12 @@ async function pipePluginJson(stream2, res, session, protocol) {
54353
54608
  }
54354
54609
  } catch {
54355
54610
  }
54356
- if (protocol === "responses") {
54611
+ if (containsRenderTagText(text)) {
54357
54612
  try {
54358
54613
  const json = JSON.parse(text);
54359
- if (containsRenderTagText(text)) {
54360
- res.end(Buffer.from(JSON.stringify(stripResponsesText(json)), "utf8"));
54361
- return;
54362
- }
54614
+ const stripped = protocol === "responses" ? stripResponsesText(json) : protocol === "anthropic" ? stripAnthropicText(json) : stripOpenaiChatText(json);
54615
+ res.end(Buffer.from(JSON.stringify(stripped), "utf8"));
54616
+ return;
54363
54617
  } catch {
54364
54618
  }
54365
54619
  }
@@ -57329,7 +57583,7 @@ ${hdrText}
57329
57583
  if (prepared.protocol === "responses") {
57330
57584
  await pipePluginResponsesWithStrip(upstream.body, res, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57331
57585
  } else {
57332
- await pipeThroughWithUsage(upstream.body, res, prepared.session, prepared.protocol);
57586
+ await pipePluginChatWithStrip(upstream.body, res, prepared.session, prepared.protocol, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
57333
57587
  }
57334
57588
  } else {
57335
57589
  await pipePluginJson(upstream.body, res, prepared.session, prepared.protocol);
@@ -57337,10 +57591,24 @@ ${hdrText}
57337
57591
  clearUpstreamTimer();
57338
57592
  return;
57339
57593
  }
57594
+ let responseBody = upstream.body;
57595
+ if (prepared !== null && prepared.stream && maxFakeCompletionRetries() > 0) {
57596
+ const resolvedBuf = await resolveFakeCompletion(upstream.body, {
57597
+ protocol: prepared.protocol,
57598
+ body,
57599
+ upstreamUrl,
57600
+ reqHeaders: buildForwardHeaders(headers),
57601
+ proxyUrl,
57602
+ signal: clientAbort.signal,
57603
+ session: prepared.session,
57604
+ log: log2
57605
+ });
57606
+ responseBody = bufferToStream(resolvedBuf);
57607
+ }
57340
57608
  const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
57341
57609
  if (!useRewriter || prepared === null) {
57342
57610
  if (prepared && prepared.resetAfterSuccess) {
57343
- const [toClient, toObserve] = upstream.body.tee();
57611
+ const [toClient, toObserve] = responseBody.tee();
57344
57612
  const observed = observeResponsesTerminalState(toObserve, prepared.stream);
57345
57613
  await pipeThrough(toClient, res);
57346
57614
  clearUpstreamTimer();
@@ -57352,7 +57620,7 @@ ${hdrText}
57352
57620
  log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
57353
57621
  }
57354
57622
  } else {
57355
- await pipeThrough(upstream.body, res);
57623
+ await pipeThrough(responseBody, res);
57356
57624
  clearUpstreamTimer();
57357
57625
  }
57358
57626
  return;
@@ -57366,10 +57634,10 @@ ${hdrText}
57366
57634
  debug: opts.debug
57367
57635
  };
57368
57636
  if (prepared.stream) {
57369
- let streamToRead = upstream.body;
57637
+ let streamToRead = responseBody;
57370
57638
  let dumpRaw;
57371
57639
  if (opts.dumpSse) {
57372
- const [a, b2] = upstream.body.tee();
57640
+ const [a, b2] = responseBody.tee();
57373
57641
  streamToRead = a;
57374
57642
  dumpRaw = dumpStreamToFile(b2, opts.dumpSse, `${Date.now()}-${safeSessionId(prepared.session.id)}-raw.sse`);
57375
57643
  }
@@ -57495,6 +57763,58 @@ async function readStreamToBuffer(stream2, maxBytes = 1 << 20) {
57495
57763
  }
57496
57764
  return Buffer.concat(chunks);
57497
57765
  }
57766
+ function bufferToStream(buf) {
57767
+ return new ReadableStream({
57768
+ start(controller) {
57769
+ controller.enqueue(new Uint8Array(buf));
57770
+ controller.close();
57771
+ }
57772
+ });
57773
+ }
57774
+ async function resolveFakeCompletion(stream2, opts) {
57775
+ let buffer = await readStreamToBuffer(stream2, fakeBufCap());
57776
+ const max = maxFakeCompletionRetries();
57777
+ const sid = opts.session.id;
57778
+ const priorStreak = opts.session.metadata.fakeCompletionStreak ?? 0;
57779
+ if (max > 0 && priorStreak < max && isFakeCompletion(opts.protocol, buffer.toString("utf8"))) {
57780
+ for (let attempt = 1; attempt <= max && !opts.signal.aborted; attempt++) {
57781
+ const hinted = injectFakeCompletionHint(opts.protocol, opts.body);
57782
+ if (hinted === null) break;
57783
+ opts.log("warn", `[${sid}] fake completion (tool-call XML, no tool block); retry ${attempt}/${max} with corrective hint`);
57784
+ let r;
57785
+ try {
57786
+ r = await fetchWithTimeout(
57787
+ opts.upstreamUrl,
57788
+ {
57789
+ method: "POST",
57790
+ headers: opts.reqHeaders,
57791
+ body: hinted,
57792
+ ...opts.proxyUrl ? { dispatcher: proxyDispatcher(opts.proxyUrl) } : {}
57793
+ },
57794
+ void 0,
57795
+ opts.signal
57796
+ );
57797
+ } catch (e) {
57798
+ opts.log("warn", `[${sid}] fake-completion retry failed: ${String(e)}; presenting original`);
57799
+ break;
57800
+ }
57801
+ try {
57802
+ if (!r.response.ok || !r.response.body) {
57803
+ opts.log("warn", `[${sid}] fake-completion retry rejected (HTTP ${r.response.status}); presenting original`);
57804
+ break;
57805
+ }
57806
+ buffer = await readStreamToBuffer(r.response.body, fakeBufCap());
57807
+ } finally {
57808
+ r.clearTimer();
57809
+ }
57810
+ if (!isFakeCompletion(opts.protocol, buffer.toString("utf8"))) break;
57811
+ }
57812
+ }
57813
+ const stillFake = isFakeCompletion(opts.protocol, buffer.toString("utf8"));
57814
+ opts.session.metadata.fakeCompletionStreak = stillFake ? priorStreak + 1 : 0;
57815
+ markDirty(opts.session);
57816
+ return buffer;
57817
+ }
57498
57818
  async function pipeThrough(stream2, res) {
57499
57819
  const reader = stream2.getReader();
57500
57820
  try {