billion-context 0.1.64 → 0.1.65
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/agent/omp.js +1 -1
- package/dist/agent/omp.js.map +1 -1
- package/dist/agent/pi.js +1 -1
- package/dist/agent/pi.js.map +1 -1
- package/dist/index.js +236 -168
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -50294,7 +50294,7 @@ function refNum2(ref) {
|
|
|
50294
50294
|
function applyRanges(ranges, ctx) {
|
|
50295
50295
|
if (ranges.length === 0) {
|
|
50296
50296
|
ctx.log("[acp-proxy: compress call had no valid ranges; nothing compressed.]");
|
|
50297
|
-
return "[Compression FAILED: no valid ranges parsed
|
|
50297
|
+
return "[Compression FAILED: no valid ranges parsed. compress requires a non-empty 'content' array of {startId, endId, summary} ranges, where startId/endId are mNNNNN message refs from the conversation. Re-issue the compress call with a valid content array.]";
|
|
50298
50298
|
}
|
|
50299
50299
|
ctx.log(`[acp-proxy: compress requested ${ranges.length} range(s): ${ranges.map((r) => `${r.startRef}\u2013${r.endRef}`).join(", ")}]`);
|
|
50300
50300
|
ctx.log(`[acp-proxy: ctx has ${ctx.messages.length} message(s), state has ${ctx.session.state.messageRefs?.byRef?.size ?? "?"} ref(s) mapped]`);
|
|
@@ -50626,6 +50626,153 @@ import { readFileSync as readFileSync3 } from "fs";
|
|
|
50626
50626
|
import { dirname as dirname4, join as join3 } from "path";
|
|
50627
50627
|
import { fileURLToPath } from "url";
|
|
50628
50628
|
|
|
50629
|
+
// src/web/page.ts
|
|
50630
|
+
import { existsSync as existsSync3 } from "fs";
|
|
50631
|
+
|
|
50632
|
+
// src/ca.ts
|
|
50633
|
+
var import_node_forge = __toESM(require_lib(), 1);
|
|
50634
|
+
import fs2 from "fs";
|
|
50635
|
+
import path6 from "path";
|
|
50636
|
+
import tls2 from "tls";
|
|
50637
|
+
var ROOT_CERT_FILE = "root-ca.pem";
|
|
50638
|
+
var ROOT_KEY_FILE = "root-ca-key.pem";
|
|
50639
|
+
var COMBINED_CA_FILE = "combined-ca.pem";
|
|
50640
|
+
var ROOT_CN = "billion-context MITM Root CA";
|
|
50641
|
+
var PLATFORM_CA_CANDIDATES = process.platform === "darwin" ? ["/etc/ssl/cert.pem", "/private/etc/ssl/cert.pem"] : [
|
|
50642
|
+
"/etc/ssl/certs/ca-certificates.crt",
|
|
50643
|
+
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
50644
|
+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
|
50645
|
+
"/etc/ssl/ca-bundle.pem",
|
|
50646
|
+
"/etc/ssl/cert.pem"
|
|
50647
|
+
];
|
|
50648
|
+
var rootCertPem;
|
|
50649
|
+
var rootKeyPem;
|
|
50650
|
+
var rootCert;
|
|
50651
|
+
var rootKey;
|
|
50652
|
+
var secureContextCache = /* @__PURE__ */ new Map();
|
|
50653
|
+
var SECURE_CONTEXT_CACHE_MAX = 64;
|
|
50654
|
+
function rootCaPath() {
|
|
50655
|
+
return path6.join(caDir(), ROOT_CERT_FILE);
|
|
50656
|
+
}
|
|
50657
|
+
function collectSystemCaPems(env = process.env) {
|
|
50658
|
+
const pems = [];
|
|
50659
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50660
|
+
const pushFile = (file) => {
|
|
50661
|
+
try {
|
|
50662
|
+
const text = fs2.readFileSync(file, "utf8");
|
|
50663
|
+
if (!text.includes("BEGIN CERTIFICATE") || seen.has(text)) return false;
|
|
50664
|
+
seen.add(text);
|
|
50665
|
+
pems.push(text);
|
|
50666
|
+
return true;
|
|
50667
|
+
} catch {
|
|
50668
|
+
}
|
|
50669
|
+
return false;
|
|
50670
|
+
};
|
|
50671
|
+
const userBundle = env.SSL_CERT_FILE?.trim();
|
|
50672
|
+
if (userBundle && pushFile(userBundle)) return pems;
|
|
50673
|
+
for (const candidate of PLATFORM_CA_CANDIDATES) {
|
|
50674
|
+
if (pushFile(candidate)) break;
|
|
50675
|
+
}
|
|
50676
|
+
return pems;
|
|
50677
|
+
}
|
|
50678
|
+
function writeCombinedBundle() {
|
|
50679
|
+
const certs = /* @__PURE__ */ new Set();
|
|
50680
|
+
for (const pem of collectSystemCaPems()) certs.add(pem.trim());
|
|
50681
|
+
for (const pem of tls2.rootCertificates) certs.add(pem.trim());
|
|
50682
|
+
certs.add(rootCertPem.trim());
|
|
50683
|
+
const body = [...certs].map((pem) => pem.endsWith("\n") ? pem : pem + "\n").join("");
|
|
50684
|
+
fs2.writeFileSync(path6.join(caDir(), COMBINED_CA_FILE), body, { mode: 420 });
|
|
50685
|
+
}
|
|
50686
|
+
function generateRootCA() {
|
|
50687
|
+
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
50688
|
+
const cert = import_node_forge.default.pki.createCertificate();
|
|
50689
|
+
cert.publicKey = keys.publicKey;
|
|
50690
|
+
cert.serialNumber = "01";
|
|
50691
|
+
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
50692
|
+
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
50693
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
|
50694
|
+
const attrs = [
|
|
50695
|
+
{ name: "commonName", value: ROOT_CN },
|
|
50696
|
+
{ name: "organizationName", value: "billion-context" }
|
|
50697
|
+
];
|
|
50698
|
+
cert.setSubject(attrs);
|
|
50699
|
+
cert.setIssuer(attrs);
|
|
50700
|
+
cert.setExtensions([
|
|
50701
|
+
{ name: "basicConstraints", cA: true },
|
|
50702
|
+
{ name: "keyUsage", keyCertSign: true, cRLSign: true, digitalSignature: true },
|
|
50703
|
+
{ name: "subjectKeyIdentifier" }
|
|
50704
|
+
]);
|
|
50705
|
+
cert.sign(keys.privateKey, import_node_forge.default.md.sha256.create());
|
|
50706
|
+
return {
|
|
50707
|
+
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
50708
|
+
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey)
|
|
50709
|
+
};
|
|
50710
|
+
}
|
|
50711
|
+
function ensureRootCA() {
|
|
50712
|
+
if (rootCertPem && rootKeyPem) {
|
|
50713
|
+
writeCombinedBundle();
|
|
50714
|
+
return;
|
|
50715
|
+
}
|
|
50716
|
+
const dir = caDir();
|
|
50717
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
50718
|
+
const certPath = path6.join(dir, ROOT_CERT_FILE);
|
|
50719
|
+
const keyPath = path6.join(dir, ROOT_KEY_FILE);
|
|
50720
|
+
if (fs2.existsSync(certPath) && fs2.existsSync(keyPath)) {
|
|
50721
|
+
rootCertPem = fs2.readFileSync(certPath, "utf8");
|
|
50722
|
+
rootKeyPem = fs2.readFileSync(keyPath, "utf8");
|
|
50723
|
+
rootCert = import_node_forge.default.pki.certificateFromPem(rootCertPem);
|
|
50724
|
+
rootKey = import_node_forge.default.pki.privateKeyFromPem(rootKeyPem);
|
|
50725
|
+
writeCombinedBundle();
|
|
50726
|
+
return;
|
|
50727
|
+
}
|
|
50728
|
+
const { cert, key } = generateRootCA();
|
|
50729
|
+
fs2.writeFileSync(certPath, cert, { mode: 420 });
|
|
50730
|
+
fs2.writeFileSync(keyPath, key, { mode: 384 });
|
|
50731
|
+
rootCertPem = cert;
|
|
50732
|
+
rootKeyPem = key;
|
|
50733
|
+
rootCert = import_node_forge.default.pki.certificateFromPem(cert);
|
|
50734
|
+
rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
|
|
50735
|
+
writeCombinedBundle();
|
|
50736
|
+
}
|
|
50737
|
+
function getSecureContext(host) {
|
|
50738
|
+
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
50739
|
+
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
50740
|
+
}
|
|
50741
|
+
const cached = secureContextCache.get(host);
|
|
50742
|
+
if (cached) {
|
|
50743
|
+
secureContextCache.delete(host);
|
|
50744
|
+
secureContextCache.set(host, cached);
|
|
50745
|
+
return cached;
|
|
50746
|
+
}
|
|
50747
|
+
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
50748
|
+
const cert = import_node_forge.default.pki.createCertificate();
|
|
50749
|
+
cert.publicKey = keys.publicKey;
|
|
50750
|
+
cert.serialNumber = Date.now().toString() + Math.floor(Math.random() * 1e6).toString();
|
|
50751
|
+
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
50752
|
+
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
50753
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2);
|
|
50754
|
+
cert.setSubject([{ name: "commonName", value: host }]);
|
|
50755
|
+
cert.setIssuer(rootCert.subject.attributes);
|
|
50756
|
+
cert.setExtensions([
|
|
50757
|
+
{ name: "basicConstraints", cA: false },
|
|
50758
|
+
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true },
|
|
50759
|
+
{ name: "extKeyUsage", serverAuth: true },
|
|
50760
|
+
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] }
|
|
50761
|
+
]);
|
|
50762
|
+
cert.sign(rootKey, import_node_forge.default.md.sha256.create());
|
|
50763
|
+
const ctx = tls2.createSecureContext({
|
|
50764
|
+
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
50765
|
+
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey),
|
|
50766
|
+
ca: rootCertPem
|
|
50767
|
+
});
|
|
50768
|
+
secureContextCache.set(host, ctx);
|
|
50769
|
+
if (secureContextCache.size > SECURE_CONTEXT_CACHE_MAX) {
|
|
50770
|
+
const oldest = secureContextCache.keys().next().value;
|
|
50771
|
+
if (oldest !== void 0) secureContextCache.delete(oldest);
|
|
50772
|
+
}
|
|
50773
|
+
return ctx;
|
|
50774
|
+
}
|
|
50775
|
+
|
|
50629
50776
|
// src/web/client.ts
|
|
50630
50777
|
var WEB_CLIENT = `
|
|
50631
50778
|
const byId=(id)=>document.getElementById(id);
|
|
@@ -50658,7 +50805,13 @@ var WEB_STYLES = `
|
|
|
50658
50805
|
`;
|
|
50659
50806
|
|
|
50660
50807
|
// src/web/page.ts
|
|
50808
|
+
function escapeHtml(value) {
|
|
50809
|
+
return value.replace(/[&<>"']/g, (char) => char === "&" ? "&" : char === "<" ? "<" : char === ">" ? ">" : char === '"' ? """ : "'");
|
|
50810
|
+
}
|
|
50661
50811
|
function renderPage(origin, version2) {
|
|
50812
|
+
const caPath = rootCaPath();
|
|
50813
|
+
const caPathEsc = escapeHtml(caPath);
|
|
50814
|
+
const caReady = existsSync3(caPath);
|
|
50662
50815
|
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>billion-context</title><style>${WEB_STYLES}</style></head><body>
|
|
50663
50816
|
<div class="app"><aside class="sidebar"><div class="brand"><div class="brand-title">billion<span>-context</span></div><div class="version">v${version2}</div></div><a class="fork-ribbon" href="https://github.com/ranxianglei/billion-context" target="_blank" rel="noopener">\u2605 Fork me on GitHub</a><nav class="nav"><button class="active" data-page="overview">\u6982\u89C8</button><button data-page="routing">\u63A5\u5165</button><button data-page="upstream">\u4E0A\u6E38</button><button data-page="sessions">\u4F1A\u8BDD</button><button data-page="settings">\u8BBE\u7F6E</button></nav></aside>
|
|
50664
50817
|
<main class="main"><section id="page-overview" class="page active"><h1>\u6982\u89C8</h1><p class="lead">\u672C\u5730\u8DEF\u7531\u4E0E\u4E0A\u6E38\u7F51\u7EDC\u76F8\u4E92\u72EC\u7ACB\uFF0CACP \u538B\u7F29\u8FD0\u884C\u5728\u4E24\u8005\u4E4B\u95F4\u3002</p><div class="grid"><div class="card"><h2>\u670D\u52A1\u5730\u5740</h2><p class="mono">${origin}</p></div><div class="card"><h2>\u5BA2\u6237\u7AEF\u63A5\u5165</h2><p class="status">\u5728"\u63A5\u5165"\u9875\u5C06\u5404\u5BA2\u6237\u7AEF\uFF08Codex / Claude Code / OpenCode / Pi \u7B49\uFF09\u7684\u6D41\u91CF\u8DEF\u7531\u5230 bili\u3002</p></div></div></section>
|
|
@@ -50673,14 +50826,14 @@ function renderPage(origin, version2) {
|
|
|
50673
50826
|
<div class="card"><div class="card-head"><h2>\u5176\u4ED6\uFF08Cursor / Aider / Continue\uFF09</h2><button class="btn small copy-btn" data-copy="${origin}/bili/">\u590D\u5236</button></div><dl class="kv"><dt>\u89C4\u5219</dt><dd>\u4EFB\u610F baseURL \u524D\u52A0 <span class="mono">${origin}/bili/</span></dd><dt>\u793A\u4F8B</dt><dd class="mono">${origin}/bili/https://api.openai.com/v1</dd></dl></div>
|
|
50674
50827
|
<h2 class="section-title">B. \u8BC1\u4E66\u63A5\u5165\u65B9\u5F0F\uFF08zcode \u7B49\u7C7B\u578B\uFF09</h2>
|
|
50675
50828
|
<p class="hint">\u4E0D\u652F\u6301\u6539 URL \u7684\u5BA2\u6237\u7AEF\uFF08endpoint \u786C\u7F16\u7801\uFF09\u9700 MITM \u900F\u660E\u4EE3\u7406\uFF0C\u8BBE HTTPS_PROXY + \u4FE1\u4EFB CA \u8BC1\u4E66\u3002</p>
|
|
50676
|
-
<div class="card"><div class="card-head"><h2>ZCode\uFF08\u7F16\u7A0B\u5957\u9910\uFF09</h2><span class="badge">MITM</span></div><dl class="kv"><dt>\u65B9\u5F0F</dt><dd>MITM \u900F\u660E\u4EE3\u7406</dd><dt>\u8BBE\u7F6E</dt><dd>Settings \u2192 Network \u2192 HTTP Proxy = <span class="mono">${origin}</span></dd><dt>CA \u8BC1\u4E66</dt><dd class="mono"
|
|
50829
|
+
<div class="card"><div class="card-head"><h2>ZCode\uFF08\u7F16\u7A0B\u5957\u9910\uFF09</h2><span class="badge">MITM</span><button class="btn small copy-btn" data-copy="${caPathEsc}">\u590D\u5236 CA \u8DEF\u5F84</button></div><dl class="kv"><dt>\u65B9\u5F0F</dt><dd>MITM \u900F\u660E\u4EE3\u7406</dd><dt>\u8BBE\u7F6E</dt><dd>Settings \u2192 Network \u2192 HTTP Proxy = <span class="mono">${origin}</span></dd><dt>CA \u8BC1\u4E66</dt><dd class="mono">${caPathEsc}${caReady ? "" : "\uFF08\u5C1A\u672A\u751F\u6210\uFF0C\u542F\u52A8\u4EE3\u7406\u540E\u81EA\u52A8\u521B\u5EFA\uFF09"}</dd></dl><p class="hint">CA \u8DEF\u5F84\u662F\u672C\u673A bili \u5B9E\u9645\u751F\u6210\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u70B9"\u590D\u5236 CA \u8DEF\u5F84"\u540E\u76F4\u63A5\u7C98\u8D34\u8FDB ZCode\u3002\u26A0\uFE0F Windows \u4E0A ZCode \u4E0D\u4F1A\u5C55\u5F00 <span class="mono">~</span>\uFF0C\u8BF7\u52FF\u624B\u586B <span class="mono">~/\u2026</span> \u5F62\u5F0F\u7684\u8DEF\u5F84\u3002</p></div></section>
|
|
50677
50830
|
<section id="page-upstream" class="page"><h1>\u4E0A\u6E38\u7F51\u7EDC</h1><p class="lead">\u63A7\u5236 bili \u5982\u4F55\u8BBF\u95EE\u771F\u5B9E Provider\uFF0C\u4E0D\u4F1A\u6539\u53D8\u5BA2\u6237\u7AEF\u7684\u672C\u5730\u8DEF\u7531\u5730\u5740\u3002</p><div class="card"><div class="card-head"><h2>\u5168\u5C40\u4EE3\u7406</h2></div><div class="modes"><label><input type="radio" name="proxy-mode" value="direct" checked>\u76F4\u8FDE\uFF08\u9ED8\u8BA4\uFF09</label><label><input type="radio" name="proxy-mode" value="manual">\u624B\u52A8\u4EE3\u7406</label><label><input type="radio" name="proxy-mode" value="auto">\u81EA\u52A8\uFF08\u8DDF\u968F\u7CFB\u7EDF\uFF09</label></div><div class="field"><label>HTTP / HTTPS Proxy</label><input id="proxy-url" class="mono" placeholder="http://127.0.0.1:7897"></div><dl class="kv"><dt>\u5F53\u524D\u6765\u6E90</dt><dd id="upstream-source">\u76F4\u8FDE</dd><dt>\u6709\u6548\u4EE3\u7406</dt><dd id="upstream-effective" class="mono">direct</dd><dt>\u7CFB\u7EDF PAC</dt><dd id="upstream-pac" class="mono">\u2014</dd><dt>\u72B6\u6001</dt><dd id="upstream-state" class="status">\u5C1A\u672A\u6D4B\u8BD5</dd></dl><div class="actions"><button id="save-upstream" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button><button id="test-upstream" class="btn">\u6D4B\u8BD5\u8FDE\u63A5</button></div></div><div class="card"><div class="card-head"><h2>\u6309 URL \u8986\u76D6</h2></div><p class="status">\u4E3A\u7279\u5B9A Provider \u5355\u72EC\u8BBE\u7F6E\u4E0A\u6E38\u4EE3\u7406\uFF0C\u8986\u76D6\u5168\u5C40\u8BBE\u7F6E\u3002\u7559\u7A7A = \u7EE7\u627F\u5168\u5C40\u3002</p><div id="upstream-overrides" class="status">\u52A0\u8F7D\u4E2D</div><div class="actions"><button id="save-overrides" class="btn primary">\u4FDD\u5B58\u8986\u76D6\u5E76\u70ED\u66F4\u65B0</button></div></div></section>
|
|
50678
50831
|
<section id="page-sessions" class="page"><div class="card-head"><div><h1>\u4F1A\u8BDD</h1><p class="lead">ACP \u538B\u7F29\u72B6\u6001\u4E0E\u4E0A\u6E38\u7528\u91CF\u3002</p></div><button id="refresh-sessions" class="btn">\u5237\u65B0</button></div><div class="card"><table><thead><tr><th>\u6807\u9898</th><th>\u534F\u8BAE</th><th>\u6807\u8BC6</th><th>\u8BF7\u6C42</th><th>\u4E0A\u4E0B\u6587</th><th>\u6700\u540E\u6D3B\u52A8</th></tr></thead><tbody id="sessions-body"></tbody></table></div></section>
|
|
50679
50832
|
<section id="page-settings" class="page"><h1>\u9AD8\u7EA7\u8BBE\u7F6E</h1><p class="lead">\u76F4\u63A5\u7F16\u8F91 providers JSON\uFF08\u6DFB\u52A0\u65B0 Provider\u3001\u914D\u7F6E\u6A21\u578B\u4E0A\u4E0B\u6587\u7A97\u53E3\u3001\u6309 URL \u4EE3\u7406\u7B49\uFF09\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u70ED\u66F4\u65B0\u3002</p><div class="card"><div class="field"><label>providers JSON</label><textarea id="providers-json">{}</textarea></div><div class="actions"><button id="save-providers" class="btn primary">\u4FDD\u5B58\u5E76\u5E94\u7528</button></div></div><div class="card"><div class="card-head"><h2>\u538B\u7F29\u53C2\u6570\uFF08\u5168\u5C40\uFF09</h2></div><p class="status">\u5168\u5C40 compress \u914D\u7F6E\uFF08modelContextLimit / maxContextLimit / emergencyThresholdPercent / nudgeGrowthTokens / preserveRecentMessages / preserveRecentTokens / minCompressRange / tiers / injectTool / injectNudge\uFF09\u3002\u4FDD\u5B58\u540E\u70ED\u66F4\u65B0\uFF0C\u65E0\u9700\u91CD\u542F\u3002\u7F6E\u7A7A = \u6062\u590D\u9ED8\u8BA4\u3002</p><div class="field"><label>compress JSON</label><textarea id="compress-json" placeholder='{"modelContextLimit": 200000}'></textarea></div><div class="actions"><button id="save-compress" class="btn primary">\u4FDD\u5B58\u5E76\u70ED\u66F4\u65B0</button></div></div></section></main></div><div id="toast" class="toast"></div><script>${WEB_CLIENT}</script></body></html>`;
|
|
50680
50833
|
}
|
|
50681
50834
|
|
|
50682
50835
|
// src/web/api.ts
|
|
50683
|
-
import { closeSync, existsSync as
|
|
50836
|
+
import { closeSync, existsSync as existsSync4, fsyncSync, mkdirSync as mkdirSync4, openSync, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
50684
50837
|
import { dirname as dirname3 } from "path";
|
|
50685
50838
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
50686
50839
|
function readConfig() {
|
|
@@ -50688,7 +50841,7 @@ function readConfig() {
|
|
|
50688
50841
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
50689
50842
|
}
|
|
50690
50843
|
function configParseError() {
|
|
50691
|
-
if (!
|
|
50844
|
+
if (!existsSync4(configFile())) return null;
|
|
50692
50845
|
const parsed = safeReadJson(configFile());
|
|
50693
50846
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return null;
|
|
50694
50847
|
return `config file is not valid JSON: ${configFile()}`;
|
|
@@ -51327,6 +51480,26 @@ function reserveOutputHeadroom(window2, maxOutput) {
|
|
|
51327
51480
|
}
|
|
51328
51481
|
return window2;
|
|
51329
51482
|
}
|
|
51483
|
+
function hoistMidSystemMessages(messages) {
|
|
51484
|
+
let lead = 0;
|
|
51485
|
+
while (lead < messages.length && (messages[lead].role === "system" || messages[lead].role === "developer")) lead++;
|
|
51486
|
+
if (lead === messages.length) return messages;
|
|
51487
|
+
let midCount = 0;
|
|
51488
|
+
for (let i = lead; i < messages.length; i++) {
|
|
51489
|
+
const r = messages[i].role;
|
|
51490
|
+
if (r === "system" || r === "developer") midCount++;
|
|
51491
|
+
}
|
|
51492
|
+
if (midCount === 0) return messages;
|
|
51493
|
+
const head = messages.slice(0, lead);
|
|
51494
|
+
const mid = [];
|
|
51495
|
+
const rest = [];
|
|
51496
|
+
for (let i = lead; i < messages.length; i++) {
|
|
51497
|
+
const r = messages[i].role;
|
|
51498
|
+
if (r === "system" || r === "developer") mid.push(messages[i]);
|
|
51499
|
+
else rest.push(messages[i]);
|
|
51500
|
+
}
|
|
51501
|
+
return [...head, ...mid, ...rest];
|
|
51502
|
+
}
|
|
51330
51503
|
function shouldReserveOutputHeadroom(protocol) {
|
|
51331
51504
|
return protocol !== "anthropic";
|
|
51332
51505
|
}
|
|
@@ -51988,7 +52161,7 @@ function createOpenaiAdapter(requestBody, clientSystem) {
|
|
|
51988
52161
|
);
|
|
51989
52162
|
return {
|
|
51990
52163
|
buildRequest(coreMessages, systemPrompt, body) {
|
|
51991
|
-
const messages = coreToOpenai(coreMessages);
|
|
52164
|
+
const messages = hoistMidSystemMessages(coreToOpenai(coreMessages));
|
|
51992
52165
|
const withSys = injectOpenaiSystem(messages, [clientSystem, systemPrompt].filter((p2) => typeof p2 === "string" && p2.length > 0));
|
|
51993
52166
|
return { ...body, messages: withSys };
|
|
51994
52167
|
},
|
|
@@ -52134,7 +52307,8 @@ function createOpenaiAdapter(requestBody, clientSystem) {
|
|
|
52134
52307
|
const fn = tc.function;
|
|
52135
52308
|
const name = typeof fn?.name === "string" ? fn.name : "";
|
|
52136
52309
|
const id = typeof tc.id === "string" ? tc.id : "";
|
|
52137
|
-
const
|
|
52310
|
+
const rawArgs = fn?.arguments;
|
|
52311
|
+
const args = typeof rawArgs === "string" ? rawArgs : rawArgs !== null && typeof rawArgs === "object" ? JSON.stringify(rawArgs) : "";
|
|
52138
52312
|
let buf = pending.get(idx);
|
|
52139
52313
|
if (!buf) {
|
|
52140
52314
|
buf = { index: idx, id, name, arguments: args };
|
|
@@ -53345,13 +53519,13 @@ function buildStatusPanel(input) {
|
|
|
53345
53519
|
|
|
53346
53520
|
// src/plugin.ts
|
|
53347
53521
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
53348
|
-
import
|
|
53349
|
-
import
|
|
53522
|
+
import fs3 from "fs";
|
|
53523
|
+
import path7 from "path";
|
|
53350
53524
|
var PROXY_VERSION = (() => {
|
|
53351
53525
|
try {
|
|
53352
53526
|
const here = fileURLToPath2(import.meta.url);
|
|
53353
|
-
const pkg =
|
|
53354
|
-
return JSON.parse(
|
|
53527
|
+
const pkg = path7.join(path7.dirname(here), "..", "package.json");
|
|
53528
|
+
return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
|
|
53355
53529
|
} catch {
|
|
53356
53530
|
return "dev";
|
|
53357
53531
|
}
|
|
@@ -53363,8 +53537,8 @@ var PLUGIN_PROTOCOL_VERSION = 1;
|
|
|
53363
53537
|
var VERSION = (() => {
|
|
53364
53538
|
try {
|
|
53365
53539
|
const here = fileURLToPath2(import.meta.url);
|
|
53366
|
-
const pkg =
|
|
53367
|
-
return JSON.parse(
|
|
53540
|
+
const pkg = path7.join(path7.dirname(here), "..", "package.json");
|
|
53541
|
+
return JSON.parse(fs3.readFileSync(pkg, "utf8")).version ?? "dev";
|
|
53368
53542
|
} catch {
|
|
53369
53543
|
return "dev";
|
|
53370
53544
|
}
|
|
@@ -53393,14 +53567,14 @@ function pluginReportedContextWindow(headers) {
|
|
|
53393
53567
|
var MAX_PLUGIN_CONVERSATIONS = 1024;
|
|
53394
53568
|
var conversations = /* @__PURE__ */ new Map();
|
|
53395
53569
|
var remembered = /* @__PURE__ */ new Map();
|
|
53396
|
-
var conversationsFile = () =>
|
|
53570
|
+
var conversationsFile = () => path7.join(stateDir(), "plugin-conversations.json");
|
|
53397
53571
|
var conversationsSaveTimer;
|
|
53398
53572
|
function writeConversationsFile() {
|
|
53399
53573
|
try {
|
|
53400
53574
|
const obj = {};
|
|
53401
53575
|
for (const [k2, v2] of conversations) obj[k2] = v2;
|
|
53402
|
-
|
|
53403
|
-
|
|
53576
|
+
fs3.mkdirSync(stateDir(), { recursive: true });
|
|
53577
|
+
fs3.writeFileSync(conversationsFile(), JSON.stringify(obj));
|
|
53404
53578
|
} catch {
|
|
53405
53579
|
}
|
|
53406
53580
|
}
|
|
@@ -53420,7 +53594,7 @@ function flushConversations() {
|
|
|
53420
53594
|
}
|
|
53421
53595
|
function loadConversations() {
|
|
53422
53596
|
try {
|
|
53423
|
-
const raw =
|
|
53597
|
+
const raw = fs3.readFileSync(conversationsFile(), "utf8");
|
|
53424
53598
|
const obj = JSON.parse(raw);
|
|
53425
53599
|
for (const [k2, v2] of Object.entries(obj)) {
|
|
53426
53600
|
if (v2 && typeof v2.sessionId === "string" && v2.sessionId.length > 0) {
|
|
@@ -53881,147 +54055,6 @@ async function pipePluginJson(stream2, res, session, protocol) {
|
|
|
53881
54055
|
// src/mitm.ts
|
|
53882
54056
|
import tls3 from "tls";
|
|
53883
54057
|
|
|
53884
|
-
// src/ca.ts
|
|
53885
|
-
var import_node_forge = __toESM(require_lib(), 1);
|
|
53886
|
-
import fs3 from "fs";
|
|
53887
|
-
import path7 from "path";
|
|
53888
|
-
import tls2 from "tls";
|
|
53889
|
-
var ROOT_CERT_FILE = "root-ca.pem";
|
|
53890
|
-
var ROOT_KEY_FILE = "root-ca-key.pem";
|
|
53891
|
-
var COMBINED_CA_FILE = "combined-ca.pem";
|
|
53892
|
-
var ROOT_CN = "billion-context MITM Root CA";
|
|
53893
|
-
var PLATFORM_CA_CANDIDATES = process.platform === "darwin" ? ["/etc/ssl/cert.pem", "/private/etc/ssl/cert.pem"] : [
|
|
53894
|
-
"/etc/ssl/certs/ca-certificates.crt",
|
|
53895
|
-
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
53896
|
-
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
|
53897
|
-
"/etc/ssl/ca-bundle.pem",
|
|
53898
|
-
"/etc/ssl/cert.pem"
|
|
53899
|
-
];
|
|
53900
|
-
var rootCertPem;
|
|
53901
|
-
var rootKeyPem;
|
|
53902
|
-
var rootCert;
|
|
53903
|
-
var rootKey;
|
|
53904
|
-
var secureContextCache = /* @__PURE__ */ new Map();
|
|
53905
|
-
var SECURE_CONTEXT_CACHE_MAX = 64;
|
|
53906
|
-
function collectSystemCaPems(env = process.env) {
|
|
53907
|
-
const pems = [];
|
|
53908
|
-
const seen = /* @__PURE__ */ new Set();
|
|
53909
|
-
const pushFile = (file) => {
|
|
53910
|
-
try {
|
|
53911
|
-
const text = fs3.readFileSync(file, "utf8");
|
|
53912
|
-
if (!text.includes("BEGIN CERTIFICATE") || seen.has(text)) return false;
|
|
53913
|
-
seen.add(text);
|
|
53914
|
-
pems.push(text);
|
|
53915
|
-
return true;
|
|
53916
|
-
} catch {
|
|
53917
|
-
}
|
|
53918
|
-
return false;
|
|
53919
|
-
};
|
|
53920
|
-
const userBundle = env.SSL_CERT_FILE?.trim();
|
|
53921
|
-
if (userBundle && pushFile(userBundle)) return pems;
|
|
53922
|
-
for (const candidate of PLATFORM_CA_CANDIDATES) {
|
|
53923
|
-
if (pushFile(candidate)) break;
|
|
53924
|
-
}
|
|
53925
|
-
return pems;
|
|
53926
|
-
}
|
|
53927
|
-
function writeCombinedBundle() {
|
|
53928
|
-
const certs = /* @__PURE__ */ new Set();
|
|
53929
|
-
for (const pem of collectSystemCaPems()) certs.add(pem.trim());
|
|
53930
|
-
for (const pem of tls2.rootCertificates) certs.add(pem.trim());
|
|
53931
|
-
certs.add(rootCertPem.trim());
|
|
53932
|
-
const body = [...certs].map((pem) => pem.endsWith("\n") ? pem : pem + "\n").join("");
|
|
53933
|
-
fs3.writeFileSync(path7.join(caDir(), COMBINED_CA_FILE), body, { mode: 420 });
|
|
53934
|
-
}
|
|
53935
|
-
function generateRootCA() {
|
|
53936
|
-
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
53937
|
-
const cert = import_node_forge.default.pki.createCertificate();
|
|
53938
|
-
cert.publicKey = keys.publicKey;
|
|
53939
|
-
cert.serialNumber = "01";
|
|
53940
|
-
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
53941
|
-
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
53942
|
-
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);
|
|
53943
|
-
const attrs = [
|
|
53944
|
-
{ name: "commonName", value: ROOT_CN },
|
|
53945
|
-
{ name: "organizationName", value: "billion-context" }
|
|
53946
|
-
];
|
|
53947
|
-
cert.setSubject(attrs);
|
|
53948
|
-
cert.setIssuer(attrs);
|
|
53949
|
-
cert.setExtensions([
|
|
53950
|
-
{ name: "basicConstraints", cA: true },
|
|
53951
|
-
{ name: "keyUsage", keyCertSign: true, cRLSign: true, digitalSignature: true },
|
|
53952
|
-
{ name: "subjectKeyIdentifier" }
|
|
53953
|
-
]);
|
|
53954
|
-
cert.sign(keys.privateKey, import_node_forge.default.md.sha256.create());
|
|
53955
|
-
return {
|
|
53956
|
-
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
53957
|
-
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey)
|
|
53958
|
-
};
|
|
53959
|
-
}
|
|
53960
|
-
function ensureRootCA() {
|
|
53961
|
-
if (rootCertPem && rootKeyPem) {
|
|
53962
|
-
writeCombinedBundle();
|
|
53963
|
-
return;
|
|
53964
|
-
}
|
|
53965
|
-
const dir = caDir();
|
|
53966
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
53967
|
-
const certPath = path7.join(dir, ROOT_CERT_FILE);
|
|
53968
|
-
const keyPath = path7.join(dir, ROOT_KEY_FILE);
|
|
53969
|
-
if (fs3.existsSync(certPath) && fs3.existsSync(keyPath)) {
|
|
53970
|
-
rootCertPem = fs3.readFileSync(certPath, "utf8");
|
|
53971
|
-
rootKeyPem = fs3.readFileSync(keyPath, "utf8");
|
|
53972
|
-
rootCert = import_node_forge.default.pki.certificateFromPem(rootCertPem);
|
|
53973
|
-
rootKey = import_node_forge.default.pki.privateKeyFromPem(rootKeyPem);
|
|
53974
|
-
writeCombinedBundle();
|
|
53975
|
-
return;
|
|
53976
|
-
}
|
|
53977
|
-
const { cert, key } = generateRootCA();
|
|
53978
|
-
fs3.writeFileSync(certPath, cert, { mode: 420 });
|
|
53979
|
-
fs3.writeFileSync(keyPath, key, { mode: 384 });
|
|
53980
|
-
rootCertPem = cert;
|
|
53981
|
-
rootKeyPem = key;
|
|
53982
|
-
rootCert = import_node_forge.default.pki.certificateFromPem(cert);
|
|
53983
|
-
rootKey = import_node_forge.default.pki.privateKeyFromPem(key);
|
|
53984
|
-
writeCombinedBundle();
|
|
53985
|
-
}
|
|
53986
|
-
function getSecureContext(host) {
|
|
53987
|
-
if (!rootCertPem || !rootKeyPem || !rootCert || !rootKey) {
|
|
53988
|
-
throw new Error("CA not initialized \u2014 call ensureRootCA() first");
|
|
53989
|
-
}
|
|
53990
|
-
const cached = secureContextCache.get(host);
|
|
53991
|
-
if (cached) {
|
|
53992
|
-
secureContextCache.delete(host);
|
|
53993
|
-
secureContextCache.set(host, cached);
|
|
53994
|
-
return cached;
|
|
53995
|
-
}
|
|
53996
|
-
const keys = import_node_forge.default.pki.rsa.generateKeyPair({ bits: 2048 });
|
|
53997
|
-
const cert = import_node_forge.default.pki.createCertificate();
|
|
53998
|
-
cert.publicKey = keys.publicKey;
|
|
53999
|
-
cert.serialNumber = Date.now().toString() + Math.floor(Math.random() * 1e6).toString();
|
|
54000
|
-
cert.validity.notBefore = /* @__PURE__ */ new Date();
|
|
54001
|
-
cert.validity.notAfter = /* @__PURE__ */ new Date();
|
|
54002
|
-
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 2);
|
|
54003
|
-
cert.setSubject([{ name: "commonName", value: host }]);
|
|
54004
|
-
cert.setIssuer(rootCert.subject.attributes);
|
|
54005
|
-
cert.setExtensions([
|
|
54006
|
-
{ name: "basicConstraints", cA: false },
|
|
54007
|
-
{ name: "keyUsage", digitalSignature: true, keyEncipherment: true },
|
|
54008
|
-
{ name: "extKeyUsage", serverAuth: true },
|
|
54009
|
-
{ name: "subjectAltName", altNames: [{ type: 2, value: host }] }
|
|
54010
|
-
]);
|
|
54011
|
-
cert.sign(rootKey, import_node_forge.default.md.sha256.create());
|
|
54012
|
-
const ctx = tls2.createSecureContext({
|
|
54013
|
-
cert: import_node_forge.default.pki.certificateToPem(cert),
|
|
54014
|
-
key: import_node_forge.default.pki.privateKeyToPem(keys.privateKey),
|
|
54015
|
-
ca: rootCertPem
|
|
54016
|
-
});
|
|
54017
|
-
secureContextCache.set(host, ctx);
|
|
54018
|
-
if (secureContextCache.size > SECURE_CONTEXT_CACHE_MAX) {
|
|
54019
|
-
const oldest = secureContextCache.keys().next().value;
|
|
54020
|
-
if (oldest !== void 0) secureContextCache.delete(oldest);
|
|
54021
|
-
}
|
|
54022
|
-
return ctx;
|
|
54023
|
-
}
|
|
54024
|
-
|
|
54025
54058
|
// src/discover.ts
|
|
54026
54059
|
import fs5 from "fs";
|
|
54027
54060
|
import os2 from "os";
|
|
@@ -54537,6 +54570,15 @@ var DEFAULT_MITM_DOMAINS = [
|
|
|
54537
54570
|
"chatgpt.com"
|
|
54538
54571
|
];
|
|
54539
54572
|
var MITM_UPSTREAM_KEY = "__biliMitmUpstream";
|
|
54573
|
+
var warnedCertRejected = false;
|
|
54574
|
+
var CERT_REJECT_RE = /alert (?:certificate unknown|unknown ca|bad certificate|certificate expired|certificate revoked|unsupported certificate)/i;
|
|
54575
|
+
function noteMitmTlsError(host, port, message, log2) {
|
|
54576
|
+
log2(`mitm ${maskHostForLog(host)}:${port} TLS error: ${message}`);
|
|
54577
|
+
if (CERT_REJECT_RE.test(message) && !warnedCertRejected) {
|
|
54578
|
+
warnedCertRejected = true;
|
|
54579
|
+
log2(`mitm ${maskHostForLog(host)}:${port} client REJECTED the MITM certificate \u2014 it does not trust bili's root CA. Install it in the client's/system trust store, then restart the client. CA: ${rootCaPath()}`);
|
|
54580
|
+
}
|
|
54581
|
+
}
|
|
54540
54582
|
var MITM_HANDSHAKE_TIMEOUT_MS_DEFAULT = 1e4;
|
|
54541
54583
|
function mitmHandshakeTimeoutMs() {
|
|
54542
54584
|
const v2 = Number.parseInt(process.env.BILI_MITM_HANDSHAKE_TIMEOUT_MS ?? "", 10);
|
|
@@ -54602,6 +54644,7 @@ function tunnelThrough(clientSocket, host, port, head, log2, proxyUrl) {
|
|
|
54602
54644
|
if (head.length > 0) upstream.write(head);
|
|
54603
54645
|
upstream.pipe(clientSocket);
|
|
54604
54646
|
clientSocket.pipe(upstream);
|
|
54647
|
+
log2(`tunnel ${maskHostForLog(host)}:${port} established (blind TCP, not decrypted)`);
|
|
54605
54648
|
const cleanup = (where, err2) => {
|
|
54606
54649
|
log2(`tunnel ${maskHostForLog(host)}:${port} ${where} closed: ${maskHostInText(err2.message, host)}`);
|
|
54607
54650
|
upstream.destroy();
|
|
@@ -54636,7 +54679,7 @@ function doMitm(server, clientSocket, host, port, head, log2) {
|
|
|
54636
54679
|
}
|
|
54637
54680
|
tlsSocket[MITM_UPSTREAM_KEY] = `https://${host}`;
|
|
54638
54681
|
tlsSocket.on("error", (err2) => {
|
|
54639
|
-
|
|
54682
|
+
noteMitmTlsError(host, port, err2.message, log2);
|
|
54640
54683
|
tlsSocket.destroy();
|
|
54641
54684
|
clientSocket.destroy();
|
|
54642
54685
|
});
|
|
@@ -55414,7 +55457,7 @@ function anthropicBetaContextWindow(headers) {
|
|
|
55414
55457
|
function safeSessionId(id) {
|
|
55415
55458
|
return (id ?? "unknown").replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
55416
55459
|
}
|
|
55417
|
-
var NO_IDENTITY_MESSAGE = "Missing stable conversation identity. Send one of the headers: x-session-id, x-session-affinity, x-acp-session, x-opencode-session, x-claude-code-session-id, session-id \u2014 or body session_id / prompt_cache_key (responses/openai). Requests replaying a conversation history are matched by content prefix affinity (#309); this one carries no usable history signal.";
|
|
55460
|
+
var NO_IDENTITY_MESSAGE = "Missing stable conversation identity. Send one of the headers: x-session-id, x-session-affinity, x-acp-session, x-opencode-session, x-claude-code-session-id, session-id \u2014 or body session_id / prompt_cache_key (responses/openai/anthropic). Requests replaying a conversation history are matched by content prefix affinity (#309); this one carries no usable history signal.";
|
|
55418
55461
|
var UPSTREAM_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
55419
55462
|
"host",
|
|
55420
55463
|
"content-length",
|
|
@@ -55753,6 +55796,11 @@ async function handle(req, res, opts, core, config, log2, instanceId) {
|
|
|
55753
55796
|
return;
|
|
55754
55797
|
}
|
|
55755
55798
|
}
|
|
55799
|
+
if (isAdminPath) {
|
|
55800
|
+
res.writeHead(404, { "content-type": "application/json" });
|
|
55801
|
+
res.end(JSON.stringify({ error: { type: "not_found", message: "no such management endpoint" } }));
|
|
55802
|
+
return;
|
|
55803
|
+
}
|
|
55756
55804
|
let bodyBuffer;
|
|
55757
55805
|
let urlPath;
|
|
55758
55806
|
let responsesCompact;
|
|
@@ -55839,9 +55887,9 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
55839
55887
|
const betaWindow = anthropicBetaContextWindow(req.headers);
|
|
55840
55888
|
const pluginWindow = pluginReportedContextWindow(req.headers);
|
|
55841
55889
|
const launcherWindow = launcherContextWindow(model);
|
|
55842
|
-
const peekWindow = host ? peekRegistryContext(model, host) : void 0;
|
|
55843
55890
|
const configuredWindow = resolveConfiguredContextLimit(opts.routes, embeddedUrl, model);
|
|
55844
|
-
|
|
55891
|
+
const peekWindow = host ? peekRegistryContext(model, host) : void 0;
|
|
55892
|
+
let native = betaWindow ?? pluginWindow ?? launcherWindow ?? configuredWindow ?? peekWindow ?? lookupContextLimit(model);
|
|
55845
55893
|
const operatorWindowTuned = resolveCompress(opts.routes, embeddedUrl, model, opts.compress).modelContextLimit !== void 0;
|
|
55846
55894
|
nativeFromFallback = !betaWindow && !pluginWindow && !launcherWindow && !peekWindow && !configuredWindow && !operatorWindowTuned;
|
|
55847
55895
|
if (!native && host) {
|
|
@@ -55876,11 +55924,16 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
55876
55924
|
convHeader ? { value: openaiSignal, source: "header", clientProvided: true } : { value: openaiSignal, source: "content-fingerprint", clientProvided: false },
|
|
55877
55925
|
parsed
|
|
55878
55926
|
) : void 0;
|
|
55879
|
-
const
|
|
55927
|
+
const anthropicSignal = protocol === "anthropic" ? conversationSignalAnthropic(parsed, convHeader) : "";
|
|
55928
|
+
const anthropicIdentity = protocol === "anthropic" ? preferPromptCacheKeyIdentity(
|
|
55929
|
+
convHeader ? { value: anthropicSignal, source: "header", clientProvided: true } : { value: anthropicSignal, source: "content-fingerprint", clientProvided: false },
|
|
55930
|
+
parsed
|
|
55931
|
+
) : void 0;
|
|
55932
|
+
const conversation = protocol === "anthropic" ? anthropicIdentity?.value ?? anthropicSignal : protocol === "openai" ? openaiIdentity?.value ?? openaiSignal : codexTurn ? codexTurn.value : subagentNamespace(
|
|
55880
55933
|
responsesIdentity?.value ?? conversationSignalResponses(parsed, convHeader),
|
|
55881
55934
|
parsed.instructions
|
|
55882
55935
|
);
|
|
55883
|
-
const clientProvided = protocol === "responses" ? responsesIdentity?.clientProvided ?? false : protocol === "openai" ? openaiIdentity?.clientProvided ?? false : !!convHeader;
|
|
55936
|
+
const clientProvided = protocol === "responses" ? responsesIdentity?.clientProvided ?? false : protocol === "openai" ? openaiIdentity?.clientProvided ?? false : protocol === "anthropic" ? anthropicIdentity?.clientProvided ?? false : !!convHeader;
|
|
55884
55937
|
let anonAffinity = null;
|
|
55885
55938
|
if (!clientProvided) {
|
|
55886
55939
|
const anonMessages = protocol === "responses" ? parsed.input ?? [] : parsed.messages ?? [];
|
|
@@ -55904,7 +55957,7 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
55904
55957
|
}
|
|
55905
55958
|
}
|
|
55906
55959
|
const sessionId = anonAffinity ? anonAffinity.sessionId : conversation;
|
|
55907
|
-
const bodyIdentity = responsesIdentity ?? openaiIdentity;
|
|
55960
|
+
const bodyIdentity = responsesIdentity ?? openaiIdentity ?? anthropicIdentity;
|
|
55908
55961
|
const affinity = affinityToken(bodyIdentity ?? {
|
|
55909
55962
|
value: clientConv ?? conversation,
|
|
55910
55963
|
source: clientConv ? "header" : "generated",
|
|
@@ -55942,7 +55995,7 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
55942
55995
|
session.metadata.effectiveContextLimit = reqConfig.modelContextLimit;
|
|
55943
55996
|
recordPluginSession(pluginConversation ?? conversation, session.id);
|
|
55944
55997
|
}
|
|
55945
|
-
if (protocol === "responses" || protocol === "openai") {
|
|
55998
|
+
if (protocol === "responses" || protocol === "openai" || protocol === "anthropic") {
|
|
55946
55999
|
const pck = parsed.prompt_cache_key;
|
|
55947
56000
|
if (typeof pck === "string" && pck.trim().length > 0) {
|
|
55948
56001
|
recordPluginSession(pck.trim(), session.id);
|
|
@@ -56065,6 +56118,10 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
56065
56118
|
const stream2 = parsed.stream === true;
|
|
56066
56119
|
++session.stats.requests;
|
|
56067
56120
|
const injectTools = opts.compress.injectTool && !pluginMode;
|
|
56121
|
+
if (isAutoModeClassifier(parsed)) {
|
|
56122
|
+
log2("info", `[${sessionId}] auto-mode classifier passthrough (skipping compress injection)`);
|
|
56123
|
+
return { body: JSON.stringify(parsed), session, processedMessages: [], originalMessages: [], anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: false, pluginMode, nudge: void 0, prompts };
|
|
56124
|
+
}
|
|
56068
56125
|
let processedMessages = [];
|
|
56069
56126
|
let originalMessages = [];
|
|
56070
56127
|
let nudge;
|
|
@@ -56111,6 +56168,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
56111
56168
|
snapshotMessages(session, originalMessages);
|
|
56112
56169
|
markDirty(session);
|
|
56113
56170
|
const rebuilt = { ...parsed, messages: rebuiltMessages, system: systemOut, tools: toolsOut };
|
|
56171
|
+
delete rebuilt.prompt_cache_key;
|
|
56114
56172
|
return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts };
|
|
56115
56173
|
}
|
|
56116
56174
|
function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode) {
|
|
@@ -56146,7 +56204,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
56146
56204
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model));
|
|
56147
56205
|
processedMessages = stripKernelSummaries(turn.messages, turn.state);
|
|
56148
56206
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
56149
|
-
rebuiltMessages = coreToOpenai(processedMessages);
|
|
56207
|
+
rebuiltMessages = hoistMidSystemMessages(coreToOpenai(processedMessages));
|
|
56150
56208
|
const sysParts = [];
|
|
56151
56209
|
if (systemText) sysParts.push(systemText);
|
|
56152
56210
|
if (shouldInject) sysParts.push(buildCompressSystemPrompt(prompts));
|
|
@@ -56330,8 +56388,10 @@ function prepareCountTokens(parsed, core, config, log2, session) {
|
|
|
56330
56388
|
const stripped = stripKernelSummaries(turn.messages, turn.state);
|
|
56331
56389
|
const rebuiltMessages = coreToAnthropic(stripped, cacheControls);
|
|
56332
56390
|
log2("info", `[${sessionId}] count_tokens pruned: ${msgs.length} \u2192 ${stripped.length} msgs`);
|
|
56391
|
+
const rebuilt = { ...parsed, messages: rebuiltMessages };
|
|
56392
|
+
delete rebuilt.prompt_cache_key;
|
|
56333
56393
|
return {
|
|
56334
|
-
body: JSON.stringify(
|
|
56394
|
+
body: JSON.stringify(rebuilt),
|
|
56335
56395
|
session,
|
|
56336
56396
|
processedMessages: [],
|
|
56337
56397
|
originalMessages: msgs,
|
|
@@ -56341,8 +56401,10 @@ function prepareCountTokens(parsed, core, config, log2, session) {
|
|
|
56341
56401
|
};
|
|
56342
56402
|
} catch (err2) {
|
|
56343
56403
|
log2("warn", `[${sessionId}] count_tokens prune failed, forwarding unchanged: ${String(err2)}`);
|
|
56404
|
+
const fallback = { ...parsed };
|
|
56405
|
+
delete fallback.prompt_cache_key;
|
|
56344
56406
|
return {
|
|
56345
|
-
body: JSON.stringify(
|
|
56407
|
+
body: JSON.stringify(fallback),
|
|
56346
56408
|
session,
|
|
56347
56409
|
processedMessages: [],
|
|
56348
56410
|
originalMessages: [],
|
|
@@ -56411,6 +56473,12 @@ function resolvePromptCacheKey(explicit, identity, routing, upstream) {
|
|
|
56411
56473
|
if (!identity.clientProvided || !shouldInjectPromptCacheKey(routing, upstream)) return void 0;
|
|
56412
56474
|
return identity.value;
|
|
56413
56475
|
}
|
|
56476
|
+
var AUTO_MODE_CLASSIFIER_STOPS = /* @__PURE__ */ new Set(["</severity>", "</block>"]);
|
|
56477
|
+
function isAutoModeClassifier(parsed) {
|
|
56478
|
+
const stops = parsed.stop_sequences;
|
|
56479
|
+
if (!Array.isArray(stops)) return false;
|
|
56480
|
+
return stops.some((s3) => typeof s3 === "string" && AUTO_MODE_CLASSIFIER_STOPS.has(s3));
|
|
56481
|
+
}
|
|
56414
56482
|
function injectSystem(parsed, opts, prompts = defaultPrompts) {
|
|
56415
56483
|
const baseText = extractSystem(parsed.system);
|
|
56416
56484
|
const parts = [];
|