billion-context 0.1.74 → 0.1.75-pr.335.311
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 +13 -0
- package/dist/agent/omp.js.map +1 -1
- package/dist/agent/pi.js +13 -0
- package/dist/agent/pi.js.map +1 -1
- package/dist/index.js +688 -328
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47856,7 +47856,7 @@ function parseCompressSettings(v2) {
|
|
|
47856
47856
|
}
|
|
47857
47857
|
out[key] = typeof obj[key] === "string" ? obj[key].trim() : obj[key];
|
|
47858
47858
|
}
|
|
47859
|
-
for (const key of ["nudgeGrowthTokens", "preserveRecentMessages", "preserveRecentTokens", "minCompressRange"]) {
|
|
47859
|
+
for (const key of ["nudgeGrowthTokens", "preserveRecentMessages", "preserveRecentTokens", "minCompressRange", "minCompressRangeChars"]) {
|
|
47860
47860
|
takeNumber(key);
|
|
47861
47861
|
}
|
|
47862
47862
|
if ("tiers" in obj) {
|
|
@@ -47922,6 +47922,7 @@ function resolveContextLimitValue(raw, nativeLimit) {
|
|
|
47922
47922
|
function mergeCompress(global2, provider, model) {
|
|
47923
47923
|
const pick = (k2) => model?.[k2] ?? provider?.[k2] ?? global2?.[k2];
|
|
47924
47924
|
const promptLevels = [global2?.prompts, provider?.prompts, model?.prompts].filter(Boolean);
|
|
47925
|
+
const rangeOf = (s3) => s3?.minCompressRangeChars ?? s3?.minCompressRange;
|
|
47925
47926
|
return {
|
|
47926
47927
|
modelContextLimit: pick("modelContextLimit"),
|
|
47927
47928
|
maxContextLimit: pick("maxContextLimit"),
|
|
@@ -47929,7 +47930,7 @@ function mergeCompress(global2, provider, model) {
|
|
|
47929
47930
|
nudgeGrowthTokens: pick("nudgeGrowthTokens"),
|
|
47930
47931
|
preserveRecentMessages: pick("preserveRecentMessages"),
|
|
47931
47932
|
preserveRecentTokens: pick("preserveRecentTokens"),
|
|
47932
|
-
|
|
47933
|
+
minCompressRangeChars: rangeOf(model) ?? rangeOf(provider) ?? rangeOf(global2),
|
|
47933
47934
|
tiers: pick("tiers"),
|
|
47934
47935
|
prompts: promptLevels.length > 0 ? Object.assign({}, ...promptLevels) : void 0,
|
|
47935
47936
|
acknowledgePromptsRisk: pick("acknowledgePromptsRisk")
|
|
@@ -47983,7 +47984,7 @@ function applyCompressSettings(base, limit, s3) {
|
|
|
47983
47984
|
preserveRecentTokens: s3.preserveRecentTokens ?? base.preserveRecentTokens,
|
|
47984
47985
|
compress: {
|
|
47985
47986
|
...base.compress,
|
|
47986
|
-
minCompressRange: s3.minCompressRange ?? base.compress.minCompressRange
|
|
47987
|
+
minCompressRange: s3.minCompressRangeChars ?? s3.minCompressRange ?? base.compress.minCompressRange
|
|
47987
47988
|
}
|
|
47988
47989
|
};
|
|
47989
47990
|
}
|
|
@@ -48008,12 +48009,22 @@ import path3 from "path";
|
|
|
48008
48009
|
// src/fetch-util.ts
|
|
48009
48010
|
var MAX_REQUEST_BYTES = 100 * 1024 * 1024;
|
|
48010
48011
|
var UPSTREAM_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
48012
|
+
var liveUpstreamTimers = /* @__PURE__ */ new Set();
|
|
48011
48013
|
async function fetchWithTimeout(url, opts, timeoutMs = UPSTREAM_TIMEOUT_MS, externalSignal) {
|
|
48012
48014
|
const controller = new AbortController();
|
|
48013
|
-
|
|
48015
|
+
const armTimer = () => {
|
|
48016
|
+
const t = setTimeout(() => {
|
|
48017
|
+
liveUpstreamTimers.delete(t);
|
|
48018
|
+
controller.abort();
|
|
48019
|
+
}, timeoutMs);
|
|
48020
|
+
liveUpstreamTimers.add(t);
|
|
48021
|
+
return t;
|
|
48022
|
+
};
|
|
48023
|
+
let timer2 = armTimer();
|
|
48014
48024
|
const rearm = () => {
|
|
48015
48025
|
clearTimeout(timer2);
|
|
48016
|
-
|
|
48026
|
+
liveUpstreamTimers.delete(timer2);
|
|
48027
|
+
timer2 = armTimer();
|
|
48017
48028
|
};
|
|
48018
48029
|
let onExternalAbort = null;
|
|
48019
48030
|
if (externalSignal) {
|
|
@@ -48025,6 +48036,7 @@ async function fetchWithTimeout(url, opts, timeoutMs = UPSTREAM_TIMEOUT_MS, exte
|
|
|
48025
48036
|
}
|
|
48026
48037
|
const cleanup = () => {
|
|
48027
48038
|
clearTimeout(timer2);
|
|
48039
|
+
liveUpstreamTimers.delete(timer2);
|
|
48028
48040
|
if (onExternalAbort && externalSignal) externalSignal.removeEventListener("abort", onExternalAbort);
|
|
48029
48041
|
};
|
|
48030
48042
|
try {
|
|
@@ -48154,6 +48166,7 @@ var CACHE_FILE = path3.join(cacheDir(), "models-dev.json");
|
|
|
48154
48166
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
48155
48167
|
var cache2 = null;
|
|
48156
48168
|
var loading = null;
|
|
48169
|
+
var warnedConflicts = /* @__PURE__ */ new Set();
|
|
48157
48170
|
var snapshotReg = null;
|
|
48158
48171
|
var snapshotMs = 0;
|
|
48159
48172
|
function bundledSnapshotRegistry() {
|
|
@@ -48326,15 +48339,22 @@ function registryLookup(reg, model, host) {
|
|
|
48326
48339
|
}
|
|
48327
48340
|
if (provider === void 0) {
|
|
48328
48341
|
const suffix = `/${model}`;
|
|
48329
|
-
let
|
|
48342
|
+
let max;
|
|
48343
|
+
const distinct = /* @__PURE__ */ new Set();
|
|
48344
|
+
const parts = [];
|
|
48330
48345
|
for (const key of Object.keys(reg)) {
|
|
48331
48346
|
if (!key.endsWith(suffix)) continue;
|
|
48332
48347
|
const ctx = reg[key].limit?.context;
|
|
48333
48348
|
if (typeof ctx !== "number" || ctx <= 0) continue;
|
|
48334
|
-
if (
|
|
48335
|
-
|
|
48349
|
+
if (max === void 0 || ctx > max) max = ctx;
|
|
48350
|
+
distinct.add(ctx);
|
|
48351
|
+
parts.push(`${key}=${ctx}`);
|
|
48336
48352
|
}
|
|
48337
|
-
|
|
48353
|
+
if (max !== void 0 && distinct.size > 1 && !warnedConflicts.has(model)) {
|
|
48354
|
+
warnedConflicts.add(model);
|
|
48355
|
+
log("warn", `[acp-registry] conflicting context windows for "${model}" (${parts.join(", ")}) \u2014 using max ${max}`);
|
|
48356
|
+
}
|
|
48357
|
+
return max;
|
|
48338
48358
|
}
|
|
48339
48359
|
return void 0;
|
|
48340
48360
|
}
|
|
@@ -48459,11 +48479,14 @@ ${summary}` }]
|
|
|
48459
48479
|
}
|
|
48460
48480
|
return { items, replaced, dropped };
|
|
48461
48481
|
}
|
|
48462
|
-
function
|
|
48463
|
-
if (
|
|
48482
|
+
function codexCompactGatePre(session, effectiveLimit) {
|
|
48483
|
+
if (effectiveLimit <= 0) return false;
|
|
48464
48484
|
if (session.stats.lastInputTokens >= effectiveLimit * 0.9) return false;
|
|
48465
48485
|
return session.state.blocks.some((b2) => b2.active);
|
|
48466
48486
|
}
|
|
48487
|
+
function codexCompactGate(session, effectiveLimit, transformOk) {
|
|
48488
|
+
return transformOk && codexCompactGatePre(session, effectiveLimit);
|
|
48489
|
+
}
|
|
48467
48490
|
function buildTriggerForgeBody(summaryText, usage, stream2) {
|
|
48468
48491
|
const compactionItem = {
|
|
48469
48492
|
type: "compaction",
|
|
@@ -49940,7 +49963,13 @@ function buildSession(parsed) {
|
|
|
49940
49963
|
metadata: parsed.metadata ?? {},
|
|
49941
49964
|
state: mergeState(parsed.state),
|
|
49942
49965
|
createdAt: parsed.createdAt ?? Date.now(),
|
|
49943
|
-
|
|
49966
|
+
// #404: lastSeen reflects the on-disk savedAt (the last real
|
|
49967
|
+
// activity), NOT the restore moment — a restart must not fabricate
|
|
49968
|
+
// activity for every session (broke fallback=latest ties, panel
|
|
49969
|
+
// freshness, and eviction ordering). Consumers that need "has this
|
|
49970
|
+
// session been used since boot" read the restored flag.
|
|
49971
|
+
lastSeen: parsed.savedAt ?? Date.now(),
|
|
49972
|
+
restored: true,
|
|
49944
49973
|
blockContents,
|
|
49945
49974
|
lastMessages: Array.isArray(parsed.messages) ? parsed.messages : void 0,
|
|
49946
49975
|
inFlight: 0,
|
|
@@ -49995,7 +50024,8 @@ async function initSessions() {
|
|
|
49995
50024
|
await store.migrateLegacyIds();
|
|
49996
50025
|
const loaded = await store.loadAll();
|
|
49997
50026
|
if (loaded.size > MAX_SESSIONS) {
|
|
49998
|
-
const
|
|
50027
|
+
const freshness = (s3) => Math.max(s3.createdAt ?? 0, s3.lastSeen ?? 0);
|
|
50028
|
+
const entries = [...loaded.entries()].sort((a, b2) => freshness(b2[1]) - freshness(a[1]));
|
|
49999
50029
|
for (const [id, s3] of entries) {
|
|
50000
50030
|
if (sessions.size >= MAX_SESSIONS) break;
|
|
50001
50031
|
sessions.set(id, s3);
|
|
@@ -50008,6 +50038,7 @@ function getSession(id, meta) {
|
|
|
50008
50038
|
const existing = sessions.get(id);
|
|
50009
50039
|
if (existing) {
|
|
50010
50040
|
existing.lastSeen = Date.now();
|
|
50041
|
+
existing.restored = false;
|
|
50011
50042
|
if (meta?.protocol && !existing.meta.protocol) existing.meta.protocol = meta.protocol;
|
|
50012
50043
|
if (meta?.upstreamOrigin && !existing.meta.upstreamOrigin) existing.meta.upstreamOrigin = meta.upstreamOrigin;
|
|
50013
50044
|
if (meta?.label && !existing.meta.label) existing.meta.label = meta.label;
|
|
@@ -50017,6 +50048,7 @@ function getSession(id, meta) {
|
|
|
50017
50048
|
const reloaded = store.loadSync(id, meta);
|
|
50018
50049
|
if (reloaded) {
|
|
50019
50050
|
reloaded.lastSeen = Date.now();
|
|
50051
|
+
reloaded.restored = false;
|
|
50020
50052
|
reloaded.persisted = true;
|
|
50021
50053
|
sessions.set(id, reloaded);
|
|
50022
50054
|
return reloaded;
|
|
@@ -50106,6 +50138,58 @@ function reconcileNativeCompactionBoundary(session) {
|
|
|
50106
50138
|
markDirty(session);
|
|
50107
50139
|
return true;
|
|
50108
50140
|
}
|
|
50141
|
+
function markCompactionBoundary(session) {
|
|
50142
|
+
session.metadata.compactionBoundary = {
|
|
50143
|
+
at: Date.now(),
|
|
50144
|
+
pending: true
|
|
50145
|
+
};
|
|
50146
|
+
markDirty(session);
|
|
50147
|
+
}
|
|
50148
|
+
function readPreCompactionArchive(session) {
|
|
50149
|
+
const raw = session.metadata.preCompactionArchive;
|
|
50150
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
50151
|
+
return raw;
|
|
50152
|
+
}
|
|
50153
|
+
return {};
|
|
50154
|
+
}
|
|
50155
|
+
function preCompactionArchiveOf(session) {
|
|
50156
|
+
return readPreCompactionArchive(session);
|
|
50157
|
+
}
|
|
50158
|
+
function applyCompactionArchive(session, activeBefore, liveRawIds, log2) {
|
|
50159
|
+
const boundary = session.metadata.compactionBoundary;
|
|
50160
|
+
if (!boundary || typeof boundary !== "object" || !boundary.pending) {
|
|
50161
|
+
return;
|
|
50162
|
+
}
|
|
50163
|
+
const activeAfter = new Set(session.state.blocks.filter((b2) => b2.active).map((b2) => b2.blockId));
|
|
50164
|
+
const deactivated = [...activeBefore].filter((id) => !activeAfter.has(id));
|
|
50165
|
+
if (deactivated.length > 0) {
|
|
50166
|
+
const archive = readPreCompactionArchive(session);
|
|
50167
|
+
const at2 = Date.now();
|
|
50168
|
+
for (const id of deactivated) {
|
|
50169
|
+
archive[id] = { at: at2, reason: "content replaced by client native compaction summary" };
|
|
50170
|
+
}
|
|
50171
|
+
session.metadata.preCompactionArchive = archive;
|
|
50172
|
+
}
|
|
50173
|
+
const { byRaw, byRef } = session.state.messageRefs;
|
|
50174
|
+
const prunedByRaw = {};
|
|
50175
|
+
for (const [rawId, ref] of Object.entries(byRaw)) {
|
|
50176
|
+
if (liveRawIds.has(rawId)) prunedByRaw[rawId] = ref;
|
|
50177
|
+
}
|
|
50178
|
+
const prunedByRef = {};
|
|
50179
|
+
for (const [ref, rawId] of Object.entries(byRef)) {
|
|
50180
|
+
if (liveRawIds.has(rawId)) prunedByRef[ref] = rawId;
|
|
50181
|
+
}
|
|
50182
|
+
session.state.messageRefs.byRaw = prunedByRaw;
|
|
50183
|
+
session.state.messageRefs.byRef = prunedByRef;
|
|
50184
|
+
session.metadata.compactionBoundary = {
|
|
50185
|
+
...boundary,
|
|
50186
|
+
pending: false,
|
|
50187
|
+
archivedAt: Date.now(),
|
|
50188
|
+
archivedBlocks: deactivated
|
|
50189
|
+
};
|
|
50190
|
+
markDirty(session);
|
|
50191
|
+
log2("info", `[${session.id}] native compaction boundary: archived ${deactivated.length} pre-compaction block(s)${deactivated.length > 0 ? ` (${deactivated.join(", ")})` : ""}; pruned ref maps to ${prunedByRaw.length} live raw id(s)`);
|
|
50192
|
+
}
|
|
50109
50193
|
function evictOldest() {
|
|
50110
50194
|
let oldestId;
|
|
50111
50195
|
let oldestSeen = Infinity;
|
|
@@ -50182,6 +50266,10 @@ function resolveDecompress(args, ctx) {
|
|
|
50182
50266
|
const blockId = rawBlockId.trim();
|
|
50183
50267
|
const block = ctx.core.decompress(blockId, ctx.session.state);
|
|
50184
50268
|
if (!block) return `[Block ${blockId} not found]`;
|
|
50269
|
+
const archived = preCompactionArchiveOf(ctx.session);
|
|
50270
|
+
if (archived[blockId] !== void 0) {
|
|
50271
|
+
return `[decompress FAILED: block ${blockId} is a pre-compaction archive \u2014 its content was in the history BEFORE the client's native compaction and is no longer reachable (replaced by the client's compaction summary). decompress is unavailable for archived blocks.]`;
|
|
50272
|
+
}
|
|
50185
50273
|
const full = args.full === true;
|
|
50186
50274
|
const cached = ctx.session.blockContents.get(blockId);
|
|
50187
50275
|
let body;
|
|
@@ -50971,7 +51059,7 @@ async function saveProviders(){const button=byId("save-providers");busy(button,t
|
|
|
50971
51059
|
async function saveCompress(){const button=byId("save-compress");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");try{const text=byId("compress-json").value.trim();const compress=text?JSON.parse(text):null;await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({compress})});toast("\u538B\u7F29\u53C2\u6570\u5DF2\u70ED\u66F4\u65B0")}catch(error){toast(String(error),true)}finally{busy(button,false)}}
|
|
50972
51060
|
async function loadOverrides(){try{const data=await loadConfig();const providers=data.providers||{};const box=byId("upstream-overrides");const entries=Object.entries(providers);if(entries.length===0){box.innerHTML='<p class="status">\u6682\u65E0 Provider\u3002\u5728"\u9AD8\u7EA7\u8BBE\u7F6E"\u9875\u6DFB\u52A0 Provider \u540E\u53EF\u5728\u6B64\u6309 URL \u914D\u7F6E\u4EE3\u7406\u3002</p>';return}box.innerHTML='<table><thead><tr><th>Provider URL</th><th>\u4E0A\u6E38\u4EE3\u7406\uFF08\u7A7A=\u7EE7\u627F\u5168\u5C40\uFF09</th></tr></thead><tbody>'+entries.map(([url,route])=>'<tr><td class="mono">'+escapeHtml(url)+'</td><td><input class="mono override-proxy" data-url="'+escapeHtml(url)+'" value="'+escapeHtml((route&&route.proxy)||"")+'" placeholder="\u7EE7\u627F\u5168\u5C40"></td></tr>').join("")+'</tbody></table>'}catch(error){byId("upstream-overrides").textContent=String(error)}}
|
|
50973
51061
|
async function saveOverrides(){const button=byId("save-overrides");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");try{const data=await loadConfig();const providers=data.providers||{};document.querySelectorAll(".override-proxy").forEach((input)=>{const url=input.dataset.url;if(!url)return;if(!providers[url])providers[url]={};const val=input.value.trim();if(val)providers[url].proxy=val;else delete providers[url].proxy});await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({providers})});await json("/__bili/config/reload",{method:"POST"});toast("\u6309 URL \u8986\u76D6\u5DF2\u70ED\u66F4\u65B0");await loadOverrides()}catch(error){toast(String(error),true)}finally{busy(button,false)}}
|
|
50974
|
-
async function loadSessions(){try{const data=await json("/__bili/stats");const rows=(data.sessions||[]).map((item)=>"<tr><td>"+escapeHtml(item.title||"\u2014")+"</td><td>"+escapeHtml(item.protocol||"\u2014")+"</td><td class=mono>"+escapeHtml(item.label||"\u2014")+"</td><td>"+escapeHtml(item.requests)+"</td><td>"+escapeHtml(item.contextTokens)+"</td><td>"+escapeHtml(new Date(item.lastSeen).toLocaleString())+"</td></tr>").join("");byId("sessions-body").innerHTML=rows||'<tr><td colspan="6">\u6682\u65E0\u4F1A\u8BDD</td></tr>'}catch(error){toast(String(error),true);throw error}}
|
|
51062
|
+
async function loadSessions(){try{const data=await json("/__bili/stats");const rows=(data.sessions||[]).map((item)=>"<tr><td>"+escapeHtml(item.title||"\u2014")+"</td><td>"+escapeHtml(item.protocol||"\u2014")+"</td><td class=mono>"+escapeHtml(item.label||"\u2014")+"</td><td>"+escapeHtml(item.requests)+"</td><td>"+escapeHtml(item.contextTokens)+"</td><td>"+escapeHtml(new Date(item.lastSeen).toLocaleString())+(item.restored?" <span class=muted>(\u6062\u590D\uFF0C\u5F00\u673A\u540E\u672A\u6D3B\u52A8)</span>":"")+"</td></tr>").join("");byId("sessions-body").innerHTML=rows||'<tr><td colspan="6">\u6682\u65E0\u4F1A\u8BDD</td></tr>'}catch(error){toast(String(error),true);throw error}}
|
|
50975
51063
|
async function refreshSessions(){const button=byId("refresh-sessions");busy(button,true,"\u5237\u65B0\u4E2D\u2026");try{await loadSessions();toast("\u4F1A\u8BDD\u5217\u8868\u5DF2\u5237\u65B0")}catch{}finally{busy(button,false)}}
|
|
50976
51064
|
document.querySelectorAll(".copy-btn").forEach((btn)=>btn.addEventListener("click",async()=>{busy(btn,true,"\u590D\u5236\u4E2D\u2026");try{await navigator.clipboard.writeText(btn.dataset.copy||"");toast("\u5DF2\u590D\u5236")}catch(e){toast(String(e),true)}finally{busy(btn,false)}}));byId("save-upstream").addEventListener("click",saveUpstream);byId("test-upstream").addEventListener("click",testUpstream);byId("save-providers").addEventListener("click",saveProviders);byId("save-compress").addEventListener("click",saveCompress);byId("save-overrides").addEventListener("click",saveOverrides);byId("refresh-sessions").addEventListener("click",refreshSessions);
|
|
50977
51065
|
Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),true));setInterval(()=>{if(byId("page-sessions").classList.contains("active"))loadSessions().catch(()=>{})},5000);
|
|
@@ -50981,7 +51069,7 @@ Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),tr
|
|
|
50981
51069
|
var WEB_STYLES = `
|
|
50982
51070
|
:root{--bg:#0f1115;--panel:#171a21;--panel2:#1e222c;--line:#2b313d;--text:#e7eaf0;--muted:#8f98a8;--blue:#6ea8fe;--green:#55c98b;--yellow:#e9b949;--red:#ef6b73;--radius:10px}
|
|
50983
51071
|
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;min-height:100vh}.app{display:grid;grid-template-columns:220px 1fr;min-height:100vh}.sidebar{border-right:1px solid var(--line);padding:22px 14px;background:#12151b;position:sticky;top:0;height:100vh}.brand{font-size:18px;font-weight:700;padding:0 10px 22px}.brand span{color:var(--blue)}.version{display:block;color:var(--muted);font-size:11px;font-weight:400;margin-top:2px}.nav{display:grid;gap:4px}.nav button{appearance:none;border:0;background:transparent;color:var(--muted);text-align:left;padding:10px 12px;border-radius:7px;cursor:pointer;font:inherit}.nav button:hover,.nav button.active{background:var(--panel2);color:var(--text)}.main{padding:32px;max-width:1050px;width:100%}.page{display:none}.page.active{display:block}h1{font-size:23px;margin:0 0 4px}h2{font-size:15px;margin:0}.lead{color:var(--muted);margin:0 0 24px}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px;margin-bottom:14px}.card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.badge{border-radius:99px;padding:3px 9px;font-size:12px;background:var(--panel2);color:var(--muted)}.badge.ok{color:var(--green)}.badge.warn{color:var(--yellow)}.badge.err{color:var(--red)}.kv{display:grid;grid-template-columns:135px 1fr;gap:10px 14px;margin:0}.kv dt{color:var(--muted)}.kv dd{margin:0;word-break:break-all}.mono{font-family:"Cascadia Code",Consolas,monospace;font-size:12px}.actions{display:flex;gap:9px;flex-wrap:wrap;margin-top:18px}.btn{border:1px solid var(--line);background:var(--panel2);color:var(--text);border-radius:7px;padding:8px 13px;cursor:pointer;font:inherit}.btn:hover{border-color:#4b5668}.btn.primary{background:var(--blue);border-color:var(--blue);color:#0b1220;font-weight:600}.btn.danger{color:var(--red)}.btn:disabled{opacity:.55;cursor:wait}.field{display:grid;gap:6px;margin:12px 0}.field label{color:var(--muted);font-size:12px}input,textarea,select{width:100%;background:#101319;color:var(--text);border:1px solid var(--line);border-radius:7px;padding:9px 10px;font:inherit}textarea{min-height:250px;font-family:"Cascadia Code",Consolas,monospace;font-size:12px;resize:vertical}.modes{display:flex;gap:18px;margin:12px 0}.modes label{display:flex;gap:7px;align-items:center;color:var(--muted)}.modes input{width:auto}.notice{border-left:3px solid var(--yellow);padding:10px 12px;background:rgba(233,185,73,.08);color:#d8c185;margin-top:14px}.status{color:var(--muted);white-space:pre-wrap}.status.ok{color:var(--green)}.status.err{color:var(--red)}table{width:100%;border-collapse:collapse}th,td{text-align:left;border-bottom:1px solid var(--line);padding:9px 8px;font-size:12px}th{color:var(--muted);font-weight:500}.toast{position:fixed;right:24px;bottom:24px;background:var(--green);color:#07140d;padding:10px 15px;border-radius:8px;opacity:0;transform:translateY(8px);transition:.2s;pointer-events:none}.toast.show{opacity:1;transform:none}.toast.err{background:var(--red);color:#1b0608}
|
|
50984
|
-
.section-title{font-size:17px;margin:28px 0 4px}.hint{color:var(--muted);margin:0 0 14px;font-size:13px}.btn.small{padding:4px 10px;font-size:12px}.config-block{background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:10px 14px;margin:8px 0 12px;overflow-x:auto;font-size:13px}.config-block code{font-family:"Cascadia Code",Consolas,monospace;color:var(--text)}.fork-ribbon{position:fixed;top:0;right:0;background:#1a1a2e;color:#fff;padding:6px 16px;font-size:12px;text-decoration:none;border-radius:0 0 0 8px;z-index:100;opacity:.8;transition:.2s}.fork-ribbon:hover{opacity:1}
|
|
51072
|
+
.section-title{font-size:17px;margin:28px 0 4px}.hint{color:var(--muted);margin:0 0 14px;font-size:13px}.muted{color:var(--muted);font-size:11px}.btn.small{padding:4px 10px;font-size:12px}.config-block{background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:10px 14px;margin:8px 0 12px;overflow-x:auto;font-size:13px}.config-block code{font-family:"Cascadia Code",Consolas,monospace;color:var(--text)}.fork-ribbon{position:fixed;top:0;right:0;background:#1a1a2e;color:#fff;padding:6px 16px;font-size:12px;text-decoration:none;border-radius:0 0 0 8px;z-index:100;opacity:.8;transition:.2s}.fork-ribbon:hover{opacity:1}
|
|
50985
51073
|
@media(max-width:760px){.app{grid-template-columns:1fr}.sidebar{height:auto;position:static;border-right:0;border-bottom:1px solid var(--line)}.nav{display:flex;overflow:auto}.main{padding:20px}.grid{grid-template-columns:1fr}.kv{grid-template-columns:110px 1fr}}
|
|
50986
51074
|
`;
|
|
50987
51075
|
|
|
@@ -51010,7 +51098,7 @@ function renderPage(origin, version2) {
|
|
|
51010
51098
|
<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>
|
|
51011
51099
|
<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>
|
|
51012
51100
|
<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>
|
|
51013
|
-
<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>`;
|
|
51101
|
+
<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 / minCompressRangeChars\uFF08\u5355\u4F4D\uFF1A\u5B57\u7B26\uFF0C\u65E7\u540D minCompressRange \u517C\u5BB9\uFF09 / 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>`;
|
|
51014
51102
|
}
|
|
51015
51103
|
|
|
51016
51104
|
// src/web/api.ts
|
|
@@ -51427,6 +51515,8 @@ function handleAcpStatus(args, ctx) {
|
|
|
51427
51515
|
const nudge = ctx.nudge;
|
|
51428
51516
|
const ranges = nudge?.compressibleRanges ?? [];
|
|
51429
51517
|
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
51518
|
+
const archive = preCompactionArchiveOf(ctx.session);
|
|
51519
|
+
const archivedIds = Object.keys(archive);
|
|
51430
51520
|
const extra = [];
|
|
51431
51521
|
if (nudge) {
|
|
51432
51522
|
extra.push("");
|
|
@@ -51436,6 +51526,13 @@ function handleAcpStatus(args, ctx) {
|
|
|
51436
51526
|
extra.push("");
|
|
51437
51527
|
extra.push(formatRanges(ranges, protectedRanges));
|
|
51438
51528
|
}
|
|
51529
|
+
if (archivedIds.length > 0) {
|
|
51530
|
+
extra.push("");
|
|
51531
|
+
extra.push(`PRE-COMPACTION ARCHIVE \u2014 ${archivedIds.length} block(s): content was replaced by the client's native compaction summary, so it is no longer in the session history and decompress is unavailable.`);
|
|
51532
|
+
for (const id of archivedIds) {
|
|
51533
|
+
extra.push(` ${id} \u2014 ${archive[id].reason}`);
|
|
51534
|
+
}
|
|
51535
|
+
}
|
|
51439
51536
|
return extra.length > 0 ? `${base}
|
|
51440
51537
|
${extra.join("\n")}` : base;
|
|
51441
51538
|
}
|
|
@@ -54239,6 +54336,32 @@ function handlePluginRegister(payload, res) {
|
|
|
54239
54336
|
queuePluginRegister(conversationId2, agent, parsed.identity === true);
|
|
54240
54337
|
res.end(JSON.stringify({ ok: true, conversationId: conversationId2, agent }));
|
|
54241
54338
|
}
|
|
54339
|
+
function handlePluginCompact(payload, res) {
|
|
54340
|
+
let parsed;
|
|
54341
|
+
try {
|
|
54342
|
+
parsed = JSON.parse(payload);
|
|
54343
|
+
} catch {
|
|
54344
|
+
res.writeHead(400, { "content-type": "application/json" });
|
|
54345
|
+
res.end(JSON.stringify({ ok: false, error: "invalid JSON body" }));
|
|
54346
|
+
return;
|
|
54347
|
+
}
|
|
54348
|
+
const conversationId2 = typeof parsed.conversationId === "string" ? parsed.conversationId.trim() : "";
|
|
54349
|
+
if (!conversationId2) {
|
|
54350
|
+
res.writeHead(400, { "content-type": "application/json" });
|
|
54351
|
+
res.end(JSON.stringify({ ok: false, error: "conversationId is required" }));
|
|
54352
|
+
return;
|
|
54353
|
+
}
|
|
54354
|
+
const entry = conversations.get(conversationId2);
|
|
54355
|
+
const session = entry ? peekSession(entry.sessionId) : void 0;
|
|
54356
|
+
if (!entry || !session) {
|
|
54357
|
+
res.writeHead(404, { "content-type": "application/json" });
|
|
54358
|
+
res.end(JSON.stringify({ ok: false, error: "unknown plugin conversation (no model request has arrived with this conversation id yet)" }));
|
|
54359
|
+
return;
|
|
54360
|
+
}
|
|
54361
|
+
markCompactionBoundary(session);
|
|
54362
|
+
entry.lastSeen = Date.now();
|
|
54363
|
+
res.end(JSON.stringify({ ok: true, conversationId: conversationId2 }));
|
|
54364
|
+
}
|
|
54242
54365
|
function handlePluginManifest(res) {
|
|
54243
54366
|
res.writeHead(200, { "content-type": "application/json" });
|
|
54244
54367
|
res.end(JSON.stringify({
|
|
@@ -54262,10 +54385,14 @@ function handlePluginStatus(conversationId2, res, fallbackLatest = false) {
|
|
|
54262
54385
|
let session = entry ? peekSession(entry.sessionId) : void 0;
|
|
54263
54386
|
let viaFallback = false;
|
|
54264
54387
|
if ((!entry || !session) && fallbackLatest) {
|
|
54265
|
-
const latest = listSessions().filter((s3) =>
|
|
54388
|
+
const latest = listSessions().filter((s3) => s3.restored !== true).sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
|
|
54266
54389
|
if (latest) {
|
|
54267
54390
|
session = latest;
|
|
54268
54391
|
viaFallback = true;
|
|
54392
|
+
} else {
|
|
54393
|
+
res.writeHead(404, { "content-type": "application/json" });
|
|
54394
|
+
res.end(JSON.stringify({ ok: false, error: "no session with activity since boot \u2014 issue a model request or pass the conversation id" }));
|
|
54395
|
+
return;
|
|
54269
54396
|
}
|
|
54270
54397
|
}
|
|
54271
54398
|
if (!session) {
|
|
@@ -54472,6 +54599,12 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
|
|
|
54472
54599
|
return new Promise((r) => res.once("drain", () => r()));
|
|
54473
54600
|
}
|
|
54474
54601
|
};
|
|
54602
|
+
const settleUsage = () => {
|
|
54603
|
+
if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
|
|
54604
|
+
applyUsageSample(session, acc, protocol);
|
|
54605
|
+
markDirty(session);
|
|
54606
|
+
}
|
|
54607
|
+
};
|
|
54475
54608
|
const pushField = (field, index, text) => {
|
|
54476
54609
|
const s3 = filterFor(field, index);
|
|
54477
54610
|
const clean = s3.filter.push(text);
|
|
@@ -54577,10 +54710,14 @@ data: ${JSON.stringify({ type: "content_block_delta", index, delta: { type: delt
|
|
|
54577
54710
|
}
|
|
54578
54711
|
const rest = flushTails();
|
|
54579
54712
|
if (rest.length > 0 && !res.destroyed && !res.writableEnded) await write(rest);
|
|
54580
|
-
|
|
54581
|
-
|
|
54582
|
-
|
|
54713
|
+
settleUsage();
|
|
54714
|
+
} catch (e) {
|
|
54715
|
+
settleUsage();
|
|
54716
|
+
if (res.destroyed || res.writableEnded) {
|
|
54717
|
+
log2?.("client aborted mid-stream");
|
|
54718
|
+
return;
|
|
54583
54719
|
}
|
|
54720
|
+
throw e;
|
|
54584
54721
|
} finally {
|
|
54585
54722
|
reader.releaseLock();
|
|
54586
54723
|
res.end();
|
|
@@ -54614,6 +54751,12 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
|
|
|
54614
54751
|
return new Promise((r) => res.once("drain", () => r()));
|
|
54615
54752
|
}
|
|
54616
54753
|
};
|
|
54754
|
+
const settleUsage = () => {
|
|
54755
|
+
if (session && (acc.inputTokens !== void 0 || acc.outputTokens !== void 0 || acc.cachedTokens !== void 0)) {
|
|
54756
|
+
applyUsageSample(session, acc, "responses");
|
|
54757
|
+
markDirty(session);
|
|
54758
|
+
}
|
|
54759
|
+
};
|
|
54617
54760
|
let lastDeltaMeta = null;
|
|
54618
54761
|
const flushTail = (after) => {
|
|
54619
54762
|
const tail = tagFilter.flush();
|
|
@@ -54686,10 +54829,14 @@ async function pipePluginResponsesWithStrip(stream2, res, session, log2) {
|
|
|
54686
54829
|
const rest = flushTail("");
|
|
54687
54830
|
if (rest.length > 0) await write(rest);
|
|
54688
54831
|
}
|
|
54689
|
-
|
|
54690
|
-
|
|
54691
|
-
|
|
54832
|
+
settleUsage();
|
|
54833
|
+
} catch (e) {
|
|
54834
|
+
settleUsage();
|
|
54835
|
+
if (res.destroyed || res.writableEnded) {
|
|
54836
|
+
log2?.("client aborted mid-stream");
|
|
54837
|
+
return;
|
|
54692
54838
|
}
|
|
54839
|
+
throw e;
|
|
54693
54840
|
} finally {
|
|
54694
54841
|
reader.releaseLock();
|
|
54695
54842
|
res.end();
|
|
@@ -54715,10 +54862,16 @@ function rebuildEvent(rawEvent, ev) {
|
|
|
54715
54862
|
async function pipePluginJson(stream2, res, session, protocol) {
|
|
54716
54863
|
const reader = stream2.getReader();
|
|
54717
54864
|
const chunks = [];
|
|
54718
|
-
|
|
54719
|
-
|
|
54720
|
-
|
|
54721
|
-
|
|
54865
|
+
try {
|
|
54866
|
+
for (; ; ) {
|
|
54867
|
+
const { done, value } = await reader.read();
|
|
54868
|
+
if (done) break;
|
|
54869
|
+
if (value && value.length > 0) chunks.push(Buffer.from(value));
|
|
54870
|
+
}
|
|
54871
|
+
} catch (e) {
|
|
54872
|
+
if (!res.writableEnded) res.end();
|
|
54873
|
+
if (res.destroyed || res.writableEnded) return;
|
|
54874
|
+
throw e;
|
|
54722
54875
|
}
|
|
54723
54876
|
reader.releaseLock();
|
|
54724
54877
|
const text = Buffer.concat(chunks).toString("utf8");
|
|
@@ -56369,7 +56522,10 @@ async function startServer(opts) {
|
|
|
56369
56522
|
await handle(req, res, opts, core, config, log2, instanceId, instanceStartedAt);
|
|
56370
56523
|
} catch (err2) {
|
|
56371
56524
|
const msg = String(err2);
|
|
56372
|
-
|
|
56525
|
+
const e = err2;
|
|
56526
|
+
const clientAbort = (e?.name === "AbortError" || /abort/i.test(String(e?.message ?? ""))) && (res.destroyed || res.writableEnded);
|
|
56527
|
+
if (clientAbort) log2("info", `client aborted mid-stream: ${msg}`);
|
|
56528
|
+
else log2("error", msg);
|
|
56373
56529
|
if (!res.headersSent) {
|
|
56374
56530
|
const status = msg.includes("exceeds") ? 413 : 502;
|
|
56375
56531
|
res.writeHead(status, { "content-type": "application/json" });
|
|
@@ -56665,6 +56821,17 @@ async function handle(req, res, opts, core, config, log2, instanceId, instanceSt
|
|
|
56665
56821
|
return;
|
|
56666
56822
|
}
|
|
56667
56823
|
}
|
|
56824
|
+
if (req.method === "POST" && req.url === "/__bili/plugin/compact") {
|
|
56825
|
+
try {
|
|
56826
|
+
const body = await readBody(req);
|
|
56827
|
+
handlePluginCompact(body.toString("utf8"), res);
|
|
56828
|
+
return;
|
|
56829
|
+
} catch (err2) {
|
|
56830
|
+
res.writeHead(err2 instanceof BodyTooLargeError ? 413 : 400, { "content-type": "application/json" });
|
|
56831
|
+
res.end(JSON.stringify({ ok: false, error: String(err2) }));
|
|
56832
|
+
return;
|
|
56833
|
+
}
|
|
56834
|
+
}
|
|
56668
56835
|
if (isAdminPath) {
|
|
56669
56836
|
res.writeHead(404, { "content-type": "application/json" });
|
|
56670
56837
|
res.end(JSON.stringify({ error: { type: "not_found", message: "no such management endpoint" } }));
|
|
@@ -56894,6 +57061,7 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
56894
57061
|
nativeFromFallback = false;
|
|
56895
57062
|
log2("info", `[${session.id}] self-healed context window: ${resolved} \u2192 ${learnedLimit} (learned from an upstream overflow)`);
|
|
56896
57063
|
}
|
|
57064
|
+
const nativeWindow = reqConfig.modelContextLimit;
|
|
56897
57065
|
if (shouldReserveOutputHeadroom(protocol)) {
|
|
56898
57066
|
const p2 = parsed;
|
|
56899
57067
|
const rawMax = p2.max_tokens ?? p2.max_completion_tokens ?? p2.max_output_tokens;
|
|
@@ -56908,7 +57076,22 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
56908
57076
|
acquireInFlight(session);
|
|
56909
57077
|
try {
|
|
56910
57078
|
await withSessionLock(session, async () => {
|
|
56911
|
-
const runPrepare = () => countTokens ? prepareCountTokens(parsed, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : responsesCompact ? prepareResponsesCompact(bodyBuffer, parsed, session, req, core, reqConfig, log2) : prepareResponses(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin);
|
|
57079
|
+
const runPrepare = () => countTokens ? prepareCountTokens(parsed, core, reqConfig, log2, session) : protocol === "anthropic" ? prepareAnthropic(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode) : protocol === "openai" ? prepareOpenai(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, pluginMode, nativeWindow) : responsesCompact ? prepareResponsesCompact(bodyBuffer, parsed, session, req, core, reqConfig, log2) : prepareResponses(parsed, req, opts, core, reqConfig, reqPrompts, log2, session, responsesIdentity, pluginMode, upstreamOrigin, nativeWindow);
|
|
57080
|
+
const isCodexCompactTrigger = protocol === "responses" && !responsesCompact && isCodexClient(req.headers) && hasCompactionTrigger(parsed.input);
|
|
57081
|
+
if (isCodexCompactTrigger) {
|
|
57082
|
+
const mode = codexCompactMode();
|
|
57083
|
+
const gatePre = codexCompactGatePre(session, reqConfig.modelContextLimit);
|
|
57084
|
+
if (mode === "intercept" && gatePre) prepared = runPrepare();
|
|
57085
|
+
if (prepared?.codexForge) {
|
|
57086
|
+
await forward(req, res, opts, prepared.body, prepared, core, reqConfig, log2, route, instanceId, affinity);
|
|
57087
|
+
rememberPluginMessages(sessionId, prepared.processedMessages, prepared.originalMessages, prepared.nudge);
|
|
57088
|
+
return;
|
|
57089
|
+
}
|
|
57090
|
+
const why = mode !== "intercept" ? "BILI_CODEX_COMPACT=pass" : !gatePre ? "gate preconditions not met" : "transform/forge failed";
|
|
57091
|
+
log2("info", `[${session.id}] codex compaction_trigger request not intercepted (${why}) \u2014 forwarding verbatim (no preflight, no rebuild, no window clamp)`);
|
|
57092
|
+
await forward(req, res, opts, bodyBuffer, null, core, reqConfig, log2, route, instanceId, affinity);
|
|
57093
|
+
return;
|
|
57094
|
+
}
|
|
56912
57095
|
prepared = runPrepare();
|
|
56913
57096
|
if (!countTokens && !responsesCompact) {
|
|
56914
57097
|
const outcome = await preflightCompressIfNeeded(
|
|
@@ -56992,7 +57175,7 @@ function diagNudge(turn, sessionId, tokenCount, limit, model, willInject) {
|
|
|
56992
57175
|
const interval = b2["nudgeGrowthTokens"] ?? 0;
|
|
56993
57176
|
const pendingT1 = b2["pendingT1"] ?? 0;
|
|
56994
57177
|
const ref = b2["growthReference"] ?? 0;
|
|
56995
|
-
const inject =
|
|
57178
|
+
const inject = willInject ? n.shouldInject ? `INJECT T${n.tier ?? "?"}` : `INJECT-ESC T${n.tier ?? "?"}` : n.shouldInject ? `ARMED-SUPPRESSED T${n.tier ?? "?"}` : "idle";
|
|
56996
57179
|
const modelTag = model ? ` model=${model}` : "";
|
|
56997
57180
|
return `[${sessionId}] nudge ${inject}: usage=${pct2} (${tokenCount}/${limit}), growth=${growth}/${floor} (ref=${ref}, interval=${interval}), pendingT1=${pendingT1}/${interval}${modelTag}, reason="${n.reason.slice(0, 120)}"`;
|
|
56998
57181
|
}
|
|
@@ -57016,6 +57199,7 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57016
57199
|
originalMessages = msgs;
|
|
57017
57200
|
extractSystem(parsed.system);
|
|
57018
57201
|
const tokenCount = session.stats.lastInputTokens;
|
|
57202
|
+
const activeBefore = new Set(session.state.blocks.filter((b2) => b2.active).map((b2) => b2.blockId));
|
|
57019
57203
|
const turn = core.processTurn({ messages: msgs, state: session.state, config, tokenCount, renderTags: "text-only" });
|
|
57020
57204
|
session.state = turn.state;
|
|
57021
57205
|
session.stats.compressCreditTokens = 0;
|
|
@@ -57027,9 +57211,10 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57027
57211
|
if (t) session.meta.title = t;
|
|
57028
57212
|
}
|
|
57029
57213
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
57030
|
-
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge
|
|
57214
|
+
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
|
|
57031
57215
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
|
|
57032
57216
|
processedMessages = stripKernelSummaries(turn.messages, turn.state);
|
|
57217
|
+
applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
|
|
57033
57218
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
57034
57219
|
rebuiltMessages = coreToAnthropic(processedMessages, cacheControls);
|
|
57035
57220
|
systemOut = injectSystem(parsed, opts, prompts);
|
|
@@ -57055,7 +57240,36 @@ function prepareAnthropic(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57055
57240
|
delete rebuilt.prompt_cache_key;
|
|
57056
57241
|
return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, anthropicSystem: parsed.system, protocol: "anthropic", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, renderTags: "text-only" };
|
|
57057
57242
|
}
|
|
57058
|
-
|
|
57243
|
+
var OUTPUT_CLAMP_MARGIN_PCT = 0.05;
|
|
57244
|
+
var OUTPUT_CLAMP_MIN_MARGIN = 2048;
|
|
57245
|
+
var OUTPUT_CLAMP_FLOOR = 1024;
|
|
57246
|
+
var EMERGENCY_NUDGE_ESCALATION_PCT = 0.7;
|
|
57247
|
+
function estimateInputTokens(processedMessages, systemText, tools, lastInputTokens) {
|
|
57248
|
+
const est = estimateCoreMessages(processedMessages) + defaultCountTokens(systemText ?? "") + defaultCountTokens(JSON.stringify(tools ?? []));
|
|
57249
|
+
return Math.max(lastInputTokens > 0 ? lastInputTokens : 0, est);
|
|
57250
|
+
}
|
|
57251
|
+
function clampOutputBudget(requested, inputEstimate, nativeWindow) {
|
|
57252
|
+
const margin = Math.max(OUTPUT_CLAMP_MIN_MARGIN, Math.ceil(inputEstimate * OUTPUT_CLAMP_MARGIN_PCT));
|
|
57253
|
+
const cap = nativeWindow - inputEstimate - margin;
|
|
57254
|
+
if (cap < OUTPUT_CLAMP_FLOOR || cap >= requested) return void 0;
|
|
57255
|
+
return cap;
|
|
57256
|
+
}
|
|
57257
|
+
function emergencyNudge(nudge, escalationPct = EMERGENCY_NUDGE_ESCALATION_PCT) {
|
|
57258
|
+
if (!nudge || nudge.shouldInject) return false;
|
|
57259
|
+
if (nudge.compressibleRanges.length === 0) return false;
|
|
57260
|
+
return nudge.contextUsage >= escalationPct;
|
|
57261
|
+
}
|
|
57262
|
+
function clampOutgoingOutput(rebuilt, field, ctx, sessionId, log2) {
|
|
57263
|
+
const raw = rebuilt[field];
|
|
57264
|
+
if (typeof raw !== "number") return;
|
|
57265
|
+
const inputEstimate = estimateInputTokens(ctx.processedMessages, ctx.systemText, ctx.tools, ctx.lastInputTokens);
|
|
57266
|
+
const capped = clampOutputBudget(raw, inputEstimate, ctx.nativeWindow);
|
|
57267
|
+
if (capped !== void 0) {
|
|
57268
|
+
rebuilt[field] = capped;
|
|
57269
|
+
log2("info", `[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`);
|
|
57270
|
+
}
|
|
57271
|
+
}
|
|
57272
|
+
function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session, pluginMode, nativeWindow) {
|
|
57059
57273
|
const sessionId = session.id;
|
|
57060
57274
|
const stream2 = parsed.stream === true;
|
|
57061
57275
|
++session.stats.requests;
|
|
@@ -57074,6 +57288,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
57074
57288
|
openaiSystemText = systemText;
|
|
57075
57289
|
originalMessages = msgs;
|
|
57076
57290
|
const tokenCount = session.stats.lastInputTokens;
|
|
57291
|
+
const activeBefore = new Set(session.state.blocks.filter((b2) => b2.active).map((b2) => b2.blockId));
|
|
57077
57292
|
const turn = core.processTurn({ messages: msgs, state: session.state, config, tokenCount, renderTags: "text-only" });
|
|
57078
57293
|
session.state = turn.state;
|
|
57079
57294
|
session.stats.compressCreditTokens = 0;
|
|
@@ -57085,9 +57300,10 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
57085
57300
|
if (t) session.meta.title = t;
|
|
57086
57301
|
}
|
|
57087
57302
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
57088
|
-
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge
|
|
57303
|
+
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
|
|
57089
57304
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
|
|
57090
57305
|
processedMessages = stripKernelSummaries(turn.messages, turn.state);
|
|
57306
|
+
applyCompactionArchive(session, activeBefore, new Set(msgs.map((m2) => m2.id)), log2);
|
|
57091
57307
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
57092
57308
|
rebuiltMessages = systemToUser(coreToOpenai(processedMessages));
|
|
57093
57309
|
const sysParts = [];
|
|
@@ -57111,6 +57327,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
57111
57327
|
processedMessages = [];
|
|
57112
57328
|
}
|
|
57113
57329
|
const rebuilt = { ...parsed, messages: rebuiltMessages, tools: toolsOut };
|
|
57330
|
+
clampOutgoingOutput(rebuilt, typeof parsed.max_completion_tokens === "number" ? "max_completion_tokens" : "max_tokens", { systemText: openaiSystemText, tools: toolsOut, processedMessages, lastInputTokens: session.stats.lastInputTokens, nativeWindow }, sessionId, log2);
|
|
57114
57331
|
delete rebuilt.prompt_cache_retention;
|
|
57115
57332
|
if (stream2 && rebuilt.stream_options === void 0) {
|
|
57116
57333
|
rebuilt.stream_options = { include_usage: true };
|
|
@@ -57119,7 +57336,7 @@ function prepareOpenai(parsed, req, opts, core, config, prompts, log2, session,
|
|
|
57119
57336
|
markDirty(session);
|
|
57120
57337
|
return { body: JSON.stringify(rebuilt), session, processedMessages, originalMessages, protocol: "openai", stream: stream2, compressInjected: injectTools, pluginMode, nudge, prompts, openaiSystemText, renderTags: "text-only" };
|
|
57121
57338
|
}
|
|
57122
|
-
function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin) {
|
|
57339
|
+
function prepareResponses(parsed, req, opts, core, config, prompts, log2, session, identity, pluginMode, upstreamOrigin, nativeWindow) {
|
|
57123
57340
|
const sessionId = session.id;
|
|
57124
57341
|
const stream2 = parsed.stream === true;
|
|
57125
57342
|
++session.stats.requests;
|
|
@@ -57176,7 +57393,7 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57176
57393
|
if (t) session.meta.title = t;
|
|
57177
57394
|
}
|
|
57178
57395
|
log2("info", diagTagSummary(turn.messages, sessionId, "text-only"));
|
|
57179
|
-
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge
|
|
57396
|
+
const willInjectNudge = opts.compress.injectNudge && !!turn.nudge && shouldInject && !isCompactionTrigger && (turn.nudge.shouldInject || emergencyNudge(turn.nudge));
|
|
57180
57397
|
log2("info", diagNudge(turn, sessionId, tokenCount, config.modelContextLimit, parsed.model, willInjectNudge));
|
|
57181
57398
|
processedMessages = stripKernelSummaries(turn.messages, turn.state);
|
|
57182
57399
|
reapOrphanBlocks(session, msgs, deactivateBlock);
|
|
@@ -57227,6 +57444,9 @@ function prepareResponses(parsed, req, opts, core, config, prompts, log2, sessio
|
|
|
57227
57444
|
log2("info", `[${sessionId}] codex compact intercepted (trigger); forged SSE with ${summaries.length} block summary(s), upstream not contacted`);
|
|
57228
57445
|
}
|
|
57229
57446
|
const rebuilt = { ...parsed, input: rebuiltInput, tools: toolsOut };
|
|
57447
|
+
if (!isCompactionTrigger) {
|
|
57448
|
+
clampOutgoingOutput(rebuilt, "max_output_tokens", { systemText: (responsesProjection?.systemParts ?? []).join("\n"), tools: toolsOut, processedMessages, lastInputTokens: session.stats.lastInputTokens, nativeWindow }, sessionId, log2);
|
|
57449
|
+
}
|
|
57230
57450
|
const promptCacheKey = resolvePromptCacheKey(
|
|
57231
57451
|
rebuilt.prompt_cache_key,
|
|
57232
57452
|
identity,
|
|
@@ -57317,7 +57537,7 @@ function prepareResponsesCompact(body, parsed, session, req, core, config, log2)
|
|
|
57317
57537
|
compressInjected: false,
|
|
57318
57538
|
resetAfterSuccess: true
|
|
57319
57539
|
};
|
|
57320
|
-
if (codexCompactMode() !== "intercept" || !isCodexClient(req.headers) || !Array.isArray(parsed.input)) {
|
|
57540
|
+
if (codexCompactMode() !== "intercept" || !isCodexClient(req.headers) || !Array.isArray(parsed.input) || !codexCompactGatePre(session, config.modelContextLimit)) {
|
|
57321
57541
|
return base;
|
|
57322
57542
|
}
|
|
57323
57543
|
const prevState = session.state;
|
|
@@ -57709,187 +57929,205 @@ ${hdrText}
|
|
|
57709
57929
|
return;
|
|
57710
57930
|
}
|
|
57711
57931
|
if (prepared?.pluginMode) {
|
|
57712
|
-
|
|
57713
|
-
|
|
57714
|
-
|
|
57715
|
-
|
|
57716
|
-
|
|
57717
|
-
|
|
57718
|
-
|
|
57719
|
-
|
|
57720
|
-
|
|
57721
|
-
|
|
57722
|
-
|
|
57723
|
-
|
|
57724
|
-
|
|
57725
|
-
|
|
57726
|
-
const resolvedBuf = await resolveFakeCompletion(upstream.body, {
|
|
57727
|
-
protocol: prepared.protocol,
|
|
57728
|
-
body,
|
|
57729
|
-
upstreamUrl,
|
|
57730
|
-
reqHeaders: buildForwardHeaders(headers),
|
|
57731
|
-
proxyUrl,
|
|
57732
|
-
signal: clientAbort.signal,
|
|
57733
|
-
session: prepared.session,
|
|
57734
|
-
log: log2
|
|
57735
|
-
});
|
|
57736
|
-
responseBody = bufferToStream(resolvedBuf);
|
|
57737
|
-
}
|
|
57738
|
-
const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
|
|
57739
|
-
if (!useRewriter || prepared === null) {
|
|
57740
|
-
if (prepared && prepared.resetAfterSuccess) {
|
|
57741
|
-
const [toClient, toObserve] = responseBody.tee();
|
|
57742
|
-
const observed = observeResponsesTerminalState(toObserve, prepared.stream);
|
|
57743
|
-
const tagLog = (msg) => log2("info", `[${prepared.session.id}] ${msg}`);
|
|
57744
|
-
if ((upstream.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
57745
|
-
await pipePluginResponsesWithStrip(toClient, res, void 0, tagLog);
|
|
57746
|
-
} else {
|
|
57747
|
-
await pipeThrough(toClient, res);
|
|
57748
|
-
}
|
|
57749
|
-
clearUpstreamTimer();
|
|
57750
|
-
const terminal = await observed;
|
|
57751
|
-
if (terminal === "completed") {
|
|
57752
|
-
markNativeCompactionBoundary(prepared.session);
|
|
57753
|
-
log2("info", `[${prepared.session.id}] native Responses compact completed; rebase scheduled for next Responses turn`);
|
|
57754
|
-
} else {
|
|
57755
|
-
log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
|
|
57932
|
+
try {
|
|
57933
|
+
let pluginBody = upstream.body;
|
|
57934
|
+
if (prepared.stream && maxFakeCompletionRetries() > 0) {
|
|
57935
|
+
const resolvedBuf = await resolveFakeCompletion(pluginBody, {
|
|
57936
|
+
protocol: prepared.protocol,
|
|
57937
|
+
body,
|
|
57938
|
+
upstreamUrl,
|
|
57939
|
+
reqHeaders: buildForwardHeaders(headers),
|
|
57940
|
+
proxyUrl,
|
|
57941
|
+
signal: clientAbort.signal,
|
|
57942
|
+
session: prepared.session,
|
|
57943
|
+
log: log2
|
|
57944
|
+
});
|
|
57945
|
+
pluginBody = bufferToStream(resolvedBuf);
|
|
57756
57946
|
}
|
|
57757
|
-
|
|
57758
|
-
|
|
57759
|
-
|
|
57760
|
-
|
|
57761
|
-
|
|
57947
|
+
if (prepared.stream) {
|
|
57948
|
+
if (prepared.protocol === "responses") {
|
|
57949
|
+
await pipePluginResponsesWithStrip(pluginBody, res, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
|
|
57950
|
+
} else {
|
|
57951
|
+
await pipePluginChatWithStrip(pluginBody, res, prepared.protocol, prepared.session, (msg) => log2("info", `[${prepared.session.id}] ${msg}`));
|
|
57952
|
+
}
|
|
57762
57953
|
} else {
|
|
57763
|
-
await
|
|
57954
|
+
await pipePluginJson(pluginBody, res, prepared.session, prepared.protocol);
|
|
57764
57955
|
}
|
|
57765
|
-
|
|
57766
|
-
} else if (prepared && (upstream.headers.get("content-type") ?? "").includes("application/json")) {
|
|
57767
|
-
await pipePluginJson(responseBody, res, void 0, prepared.protocol);
|
|
57768
|
-
clearUpstreamTimer();
|
|
57769
|
-
} else {
|
|
57770
|
-
await pipeThrough(responseBody, res);
|
|
57956
|
+
} finally {
|
|
57771
57957
|
clearUpstreamTimer();
|
|
57772
57958
|
}
|
|
57773
57959
|
return;
|
|
57774
57960
|
}
|
|
57775
|
-
|
|
57776
|
-
|
|
57777
|
-
|
|
57778
|
-
|
|
57779
|
-
|
|
57780
|
-
|
|
57781
|
-
|
|
57782
|
-
|
|
57783
|
-
|
|
57784
|
-
|
|
57785
|
-
|
|
57786
|
-
|
|
57787
|
-
|
|
57788
|
-
|
|
57789
|
-
|
|
57790
|
-
|
|
57791
|
-
|
|
57792
|
-
|
|
57793
|
-
|
|
57794
|
-
|
|
57795
|
-
|
|
57796
|
-
|
|
57797
|
-
|
|
57798
|
-
|
|
57799
|
-
|
|
57800
|
-
|
|
57801
|
-
|
|
57802
|
-
|
|
57803
|
-
|
|
57804
|
-
|
|
57805
|
-
|
|
57806
|
-
|
|
57807
|
-
|
|
57808
|
-
}
|
|
57809
|
-
|
|
57810
|
-
|
|
57811
|
-
|
|
57812
|
-
|
|
57813
|
-
|
|
57814
|
-
|
|
57815
|
-
systemPrompt,
|
|
57816
|
-
clientAbort.signal
|
|
57817
|
-
);
|
|
57818
|
-
let protocolFragmentWarned = false;
|
|
57819
|
-
for await (const chunk of loop) {
|
|
57820
|
-
if (res.destroyed || res.writableEnded) break;
|
|
57821
|
-
{
|
|
57822
|
-
const s3 = chunk.toString("utf8");
|
|
57823
|
-
if (s3.includes("<acp ") || s3.includes("</acp")) {
|
|
57824
|
-
log2("warn", `[${prepared.session.id}] tag echo: ${prepared.protocol} response stream contains <acp tag`);
|
|
57825
|
-
} else if (!protocolFragmentWarned && containsToolCallXmlFragment(s3)) {
|
|
57826
|
-
protocolFragmentWarned = true;
|
|
57827
|
-
log2("warn", `[${prepared.session.id}] tag echo: ${prepared.protocol} response stream contains tool-call XML fragment (possible tag echo; not stripped)`);
|
|
57828
|
-
}
|
|
57829
|
-
}
|
|
57830
|
-
res.write(chunk);
|
|
57831
|
-
if (res.writableNeedDrain) {
|
|
57832
|
-
await Promise.race([
|
|
57833
|
-
new Promise((r) => res.once("drain", () => r())),
|
|
57834
|
-
new Promise((r) => res.once("close", () => r()))
|
|
57835
|
-
]);
|
|
57961
|
+
let responseBody = upstream.body;
|
|
57962
|
+
try {
|
|
57963
|
+
if (prepared !== null && prepared.stream && maxFakeCompletionRetries() > 0) {
|
|
57964
|
+
const resolvedBuf = await resolveFakeCompletion(upstream.body, {
|
|
57965
|
+
protocol: prepared.protocol,
|
|
57966
|
+
body,
|
|
57967
|
+
upstreamUrl,
|
|
57968
|
+
reqHeaders: buildForwardHeaders(headers),
|
|
57969
|
+
proxyUrl,
|
|
57970
|
+
signal: clientAbort.signal,
|
|
57971
|
+
session: prepared.session,
|
|
57972
|
+
log: log2
|
|
57973
|
+
});
|
|
57974
|
+
responseBody = bufferToStream(resolvedBuf);
|
|
57975
|
+
}
|
|
57976
|
+
const useRewriter = prepared !== null && prepared.compressInjected && prepared.processedMessages.length > 0;
|
|
57977
|
+
if (!useRewriter || prepared === null) {
|
|
57978
|
+
if (prepared && prepared.resetAfterSuccess) {
|
|
57979
|
+
const [toClient, toObserve] = responseBody.tee();
|
|
57980
|
+
const observed = observeResponsesTerminalState(toObserve, prepared.stream);
|
|
57981
|
+
const tagLog = (msg) => log2("info", `[${prepared.session.id}] ${msg}`);
|
|
57982
|
+
if ((upstream.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
57983
|
+
await pipePluginResponsesWithStrip(toClient, res, void 0, tagLog);
|
|
57984
|
+
} else {
|
|
57985
|
+
await pipeThrough(toClient, res);
|
|
57986
|
+
}
|
|
57987
|
+
const terminal = await observed;
|
|
57988
|
+
if (terminal === "completed") {
|
|
57989
|
+
markNativeCompactionBoundary(prepared.session);
|
|
57990
|
+
log2("info", `[${prepared.session.id}] native Responses compact completed; rebase scheduled for next Responses turn`);
|
|
57991
|
+
} else {
|
|
57992
|
+
log2("warn", `[${prepared.session.id}] native compact response terminal=${terminal}; rebase NOT scheduled`);
|
|
57993
|
+
}
|
|
57994
|
+
} else if (prepared && prepared.stream && (upstream.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
57995
|
+
const p2 = prepared;
|
|
57996
|
+
const tagLog = (msg) => log2("info", `[${p2.session.id}] ${msg}`);
|
|
57997
|
+
if (p2.protocol === "responses") {
|
|
57998
|
+
await pipePluginResponsesWithStrip(responseBody, res, void 0, tagLog);
|
|
57999
|
+
} else {
|
|
58000
|
+
await pipePluginChatWithStrip(responseBody, res, p2.protocol, void 0, tagLog);
|
|
57836
58001
|
}
|
|
57837
|
-
|
|
58002
|
+
} else if (prepared && (upstream.headers.get("content-type") ?? "").includes("application/json")) {
|
|
58003
|
+
await pipePluginJson(responseBody, res, void 0, prepared.protocol);
|
|
58004
|
+
} else {
|
|
58005
|
+
await pipeThrough(responseBody, res);
|
|
57838
58006
|
}
|
|
57839
|
-
|
|
57840
|
-
} catch (e) {
|
|
57841
|
-
emitStreamError(res, prepared.protocol, e?.message ?? String(e), (m2) => log2("error", `[${prepared.session.id}] ${m2}`));
|
|
57842
|
-
} finally {
|
|
57843
|
-
clearUpstreamTimer();
|
|
57844
|
-
if (dumpRaw) await dumpRaw;
|
|
58007
|
+
return;
|
|
57845
58008
|
}
|
|
57846
|
-
|
|
57847
|
-
|
|
57848
|
-
|
|
57849
|
-
|
|
58009
|
+
const ctx = {
|
|
58010
|
+
core,
|
|
58011
|
+
config,
|
|
58012
|
+
messages: prepared.originalMessages,
|
|
58013
|
+
session: prepared.session,
|
|
58014
|
+
log: (msg) => log2("info", `[${prepared.session.id}] ${msg}`),
|
|
58015
|
+
debug: opts.debug
|
|
58016
|
+
};
|
|
58017
|
+
if (prepared.stream) {
|
|
58018
|
+
let streamToRead = responseBody;
|
|
58019
|
+
let dumpRaw;
|
|
58020
|
+
if (opts.dumpSse) {
|
|
58021
|
+
const [a, b2] = responseBody.tee();
|
|
58022
|
+
streamToRead = a;
|
|
58023
|
+
dumpRaw = dumpStreamToFile(b2, opts.dumpSse, `${Date.now()}-${safeSessionId(prepared.session.id)}-raw.sse`);
|
|
58024
|
+
}
|
|
57850
58025
|
try {
|
|
57851
|
-
|
|
57852
|
-
|
|
57853
|
-
|
|
57854
|
-
|
|
57855
|
-
|
|
57856
|
-
|
|
57857
|
-
|
|
57858
|
-
|
|
57859
|
-
|
|
57860
|
-
|
|
57861
|
-
|
|
57862
|
-
|
|
57863
|
-
|
|
57864
|
-
|
|
57865
|
-
|
|
57866
|
-
|
|
57867
|
-
|
|
57868
|
-
|
|
57869
|
-
|
|
57870
|
-
|
|
57871
|
-
|
|
57872
|
-
|
|
58026
|
+
const parsedReq = JSON.parse(typeof body === "string" ? body : body.toString("utf8"));
|
|
58027
|
+
const reqHeaders = buildForwardHeaders(headers);
|
|
58028
|
+
const textProtocol = prepared.protocol === "responses" && !!prepared.responsesTextProtocol;
|
|
58029
|
+
const systemPrompt = textProtocol ? buildCompressHybridSystemPrompt(prepared.prompts ?? defaultPrompts) : buildCompressSystemPrompt(prepared.prompts ?? defaultPrompts);
|
|
58030
|
+
const adapter = pickAdapter(prepared.protocol, parsedReq, textProtocol, prepared.responsesProjection, prepared.anthropicSystem, prepared.openaiSystemText);
|
|
58031
|
+
const refreshFolded = (current) => {
|
|
58032
|
+
const turn = core.processTurn({
|
|
58033
|
+
messages: prepared.originalMessages,
|
|
58034
|
+
state: prepared.session.state,
|
|
58035
|
+
config,
|
|
58036
|
+
tokenCount: prepared.session.stats.lastInputTokens,
|
|
58037
|
+
renderTags: prepared.renderTags ?? "text-only"
|
|
58038
|
+
});
|
|
58039
|
+
prepared.session.state = turn.state;
|
|
58040
|
+
const records = current.filter((m2) => typeof m2.id === "string" && m2.id.startsWith("acp_loop_"));
|
|
58041
|
+
return stripKernelSummaries([...turn.messages, ...records], turn.state);
|
|
58042
|
+
};
|
|
58043
|
+
const loop = runCompressLoop(
|
|
58044
|
+
streamToRead,
|
|
58045
|
+
{ core, config, messages: prepared.processedMessages.length > 0 ? prepared.processedMessages : prepared.originalMessages, compressMessages: prepared.originalMessages, session: prepared.session, log: ctx.log, proxyUrl, protocol: prepared.protocol, textProtocol, debug: opts.debug, nudge: prepared.nudge, refreshFolded },
|
|
58046
|
+
parsedReq,
|
|
58047
|
+
{ url: upstreamUrl, headers: reqHeaders },
|
|
58048
|
+
adapter,
|
|
58049
|
+
systemPrompt,
|
|
58050
|
+
clientAbort.signal
|
|
58051
|
+
);
|
|
58052
|
+
let protocolFragmentWarned = false;
|
|
58053
|
+
for await (const chunk of loop) {
|
|
58054
|
+
if (res.destroyed || res.writableEnded) break;
|
|
58055
|
+
{
|
|
58056
|
+
const s3 = chunk.toString("utf8");
|
|
58057
|
+
if (s3.includes("<acp ") || s3.includes("</acp")) {
|
|
58058
|
+
log2("warn", `[${prepared.session.id}] tag echo: ${prepared.protocol} response stream contains <acp tag`);
|
|
58059
|
+
} else if (!protocolFragmentWarned && containsToolCallXmlFragment(s3)) {
|
|
58060
|
+
protocolFragmentWarned = true;
|
|
58061
|
+
log2("warn", `[${prepared.session.id}] tag echo: ${prepared.protocol} response stream contains tool-call XML fragment (possible tag echo; not stripped)`);
|
|
58062
|
+
}
|
|
58063
|
+
}
|
|
58064
|
+
res.write(chunk);
|
|
58065
|
+
if (res.writableNeedDrain) {
|
|
58066
|
+
await Promise.race([
|
|
58067
|
+
new Promise((r) => res.once("drain", () => r())),
|
|
58068
|
+
new Promise((r) => res.once("close", () => r()))
|
|
58069
|
+
]);
|
|
57873
58070
|
}
|
|
57874
|
-
|
|
57875
|
-
if (typeof out === "number") prepared.session.stats.outputTokens += out;
|
|
58071
|
+
if (res.destroyed || res.writableEnded) break;
|
|
57876
58072
|
}
|
|
57877
|
-
|
|
57878
|
-
|
|
57879
|
-
|
|
57880
|
-
|
|
57881
|
-
|
|
57882
|
-
|
|
58073
|
+
res.end();
|
|
58074
|
+
} catch (e) {
|
|
58075
|
+
emitStreamError(res, prepared.protocol, e?.message ?? String(e), (m2) => log2("error", `[${prepared.session.id}] ${m2}`));
|
|
58076
|
+
} finally {
|
|
58077
|
+
clearUpstreamTimer();
|
|
58078
|
+
if (dumpRaw) await dumpRaw;
|
|
58079
|
+
markDirty(prepared.session);
|
|
58080
|
+
}
|
|
58081
|
+
} else {
|
|
58082
|
+
try {
|
|
58083
|
+
const buf = await upstream.arrayBuffer();
|
|
58084
|
+
const text = Buffer.from(buf).toString("utf8");
|
|
58085
|
+
try {
|
|
58086
|
+
let json = JSON.parse(text);
|
|
58087
|
+
if (prepared.protocol === "responses" && prepared.responsesTextProtocol) {
|
|
58088
|
+
const requestBody = JSON.parse(typeof body === "string" ? body : body.toString("utf8"));
|
|
58089
|
+
const requestHeaders = buildForwardHeaders(headers);
|
|
58090
|
+
json = await compressLoopResponsesJson(
|
|
58091
|
+
json,
|
|
58092
|
+
{ core, config, messages: prepared.originalMessages, session: prepared.session, log: ctx.log, proxyUrl, textProtocol: true },
|
|
58093
|
+
requestBody,
|
|
58094
|
+
{ url: upstreamUrl, headers: requestHeaders }
|
|
58095
|
+
);
|
|
58096
|
+
}
|
|
58097
|
+
const u2 = json.usage ?? {};
|
|
58098
|
+
const { total, cached } = usageTotals(prepared.protocol, u2);
|
|
58099
|
+
if (typeof total === "number") {
|
|
58100
|
+
prepared.session.stats.inputTokens += total;
|
|
58101
|
+
prepared.session.stats.lastInputTokens = Math.max(
|
|
58102
|
+
0,
|
|
58103
|
+
total - (prepared.session.stats.compressCreditTokens ?? 0)
|
|
58104
|
+
);
|
|
58105
|
+
if (typeof cached === "number") {
|
|
58106
|
+
prepared.session.stats.cachedTokens += cached;
|
|
58107
|
+
prepared.session.stats.cacheSamples += 1;
|
|
58108
|
+
}
|
|
58109
|
+
const out = u2.completion_tokens ?? u2.output_tokens;
|
|
58110
|
+
if (typeof out === "number") prepared.session.stats.outputTokens += out;
|
|
58111
|
+
}
|
|
58112
|
+
if (prepared.protocol === "openai") {
|
|
58113
|
+
rewriteOpenaiJsonResponse(json, ctx);
|
|
58114
|
+
} else if (prepared.protocol === "responses") {
|
|
58115
|
+
rewriteResponsesJsonResponse(json, ctx);
|
|
58116
|
+
} else {
|
|
58117
|
+
rewriteJsonResponse(json, ctx);
|
|
58118
|
+
}
|
|
58119
|
+
res.end(JSON.stringify(json));
|
|
58120
|
+
} catch {
|
|
58121
|
+
res.end(text);
|
|
57883
58122
|
}
|
|
57884
|
-
|
|
57885
|
-
|
|
57886
|
-
|
|
58123
|
+
} finally {
|
|
58124
|
+
clearUpstreamTimer();
|
|
58125
|
+
markDirty(prepared.session);
|
|
57887
58126
|
}
|
|
57888
|
-
} finally {
|
|
57889
|
-
clearUpstreamTimer();
|
|
57890
58127
|
}
|
|
58128
|
+
} finally {
|
|
58129
|
+
clearUpstreamTimer();
|
|
57891
58130
|
}
|
|
57892
|
-
markDirty(prepared.session);
|
|
57893
58131
|
}
|
|
57894
58132
|
async function readStreamToBuffer(stream2, maxBytes = 1 << 20) {
|
|
57895
58133
|
const reader = stream2.getReader();
|
|
@@ -58034,7 +58272,8 @@ function sendStats(res) {
|
|
|
58034
58272
|
outputTokens: s3.stats.outputTokens,
|
|
58035
58273
|
cacheSamples: s3.stats.cacheSamples,
|
|
58036
58274
|
cacheHitPct: s3.stats.cacheSamples > 0 && s3.stats.inputTokens > 0 ? Math.round(s3.stats.cachedTokens / s3.stats.inputTokens * 100) : null,
|
|
58037
|
-
lastSeen: new Date(s3.lastSeen).toISOString()
|
|
58275
|
+
lastSeen: new Date(s3.lastSeen).toISOString(),
|
|
58276
|
+
restored: s3.restored === true
|
|
58038
58277
|
}));
|
|
58039
58278
|
res.writeHead(200, { "content-type": "application/json" });
|
|
58040
58279
|
res.end(JSON.stringify({ sessions: sessions2 }, null, 2));
|
|
@@ -62333,19 +62572,20 @@ function livePidHoldsOverlay(overlay) {
|
|
|
62333
62572
|
function linkOverlayEntry(realHome, overlay, entry) {
|
|
62334
62573
|
const target = path14.join(realHome, entry);
|
|
62335
62574
|
const link = path14.join(overlay, entry);
|
|
62336
|
-
try {
|
|
62337
|
-
fs11.symlinkSync(target, link);
|
|
62338
|
-
return true;
|
|
62339
|
-
} catch (err2) {
|
|
62340
|
-
const code = err2.code;
|
|
62341
|
-
if (code !== "EPERM" && code !== "EACCES" && code !== "EINVAL") return false;
|
|
62342
|
-
}
|
|
62343
62575
|
let st2;
|
|
62344
62576
|
try {
|
|
62345
62577
|
st2 = fs11.lstatSync(target);
|
|
62346
62578
|
} catch {
|
|
62347
62579
|
return false;
|
|
62348
62580
|
}
|
|
62581
|
+
const kind = st2.isDirectory() ? process.platform === "win32" ? "junction" : "dir" : "file";
|
|
62582
|
+
try {
|
|
62583
|
+
fs11.symlinkSync(target, link, kind);
|
|
62584
|
+
return true;
|
|
62585
|
+
} catch (err2) {
|
|
62586
|
+
const code = err2.code;
|
|
62587
|
+
if (code !== "EPERM" && code !== "EACCES" && code !== "EINVAL") return false;
|
|
62588
|
+
}
|
|
62349
62589
|
if (st2.isDirectory()) {
|
|
62350
62590
|
try {
|
|
62351
62591
|
fs11.symlinkSync(target, link, "junction");
|
|
@@ -62376,17 +62616,39 @@ function isWriteThroughHardlink(overlayPath, realPath, st2) {
|
|
|
62376
62616
|
}
|
|
62377
62617
|
}
|
|
62378
62618
|
function sqliteSetMembers(base) {
|
|
62379
|
-
return [base, `${base}-wal`, `${base}-shm`];
|
|
62619
|
+
return [base, `${base}-wal`, `${base}-shm`, `${base}-journal`];
|
|
62620
|
+
}
|
|
62621
|
+
function freeConflictName(dst) {
|
|
62622
|
+
let candidate = `${dst}.bili-conflict`;
|
|
62623
|
+
let n = 1;
|
|
62624
|
+
while (n < 1e5) {
|
|
62625
|
+
try {
|
|
62626
|
+
fs11.lstatSync(candidate);
|
|
62627
|
+
candidate = `${dst}.bili-conflict.${n}`;
|
|
62628
|
+
n += 1;
|
|
62629
|
+
} catch {
|
|
62630
|
+
return candidate;
|
|
62631
|
+
}
|
|
62632
|
+
}
|
|
62633
|
+
return candidate;
|
|
62380
62634
|
}
|
|
62381
62635
|
function mergeSqliteSet(overlay, realHome, base) {
|
|
62382
|
-
const members = sqliteSetMembers(base)
|
|
62636
|
+
const members = sqliteSetMembers(base);
|
|
62637
|
+
const statFile = (dir, m2) => {
|
|
62383
62638
|
try {
|
|
62384
|
-
|
|
62639
|
+
const st2 = fs11.lstatSync(path14.join(dir, m2));
|
|
62640
|
+
return st2.isFile() ? st2 : void 0;
|
|
62385
62641
|
} catch {
|
|
62386
|
-
return
|
|
62642
|
+
return void 0;
|
|
62387
62643
|
}
|
|
62388
|
-
}
|
|
62389
|
-
|
|
62644
|
+
};
|
|
62645
|
+
const oMain = statFile(overlay, base);
|
|
62646
|
+
const rMain = statFile(realHome, base);
|
|
62647
|
+
let winner;
|
|
62648
|
+
if (oMain && rMain) winner = rMain.mtimeMs >= oMain.mtimeMs ? "real" : "overlay";
|
|
62649
|
+
else if (oMain) winner = "overlay";
|
|
62650
|
+
else if (rMain) winner = "real";
|
|
62651
|
+
else winner = "orphan";
|
|
62390
62652
|
const undo = [];
|
|
62391
62653
|
const rollback = () => {
|
|
62392
62654
|
for (const step of undo.reverse()) {
|
|
@@ -62397,46 +62659,39 @@ function mergeSqliteSet(overlay, realHome, base) {
|
|
|
62397
62659
|
}
|
|
62398
62660
|
undo.length = 0;
|
|
62399
62661
|
};
|
|
62662
|
+
const movePreserving = (src, dst) => {
|
|
62663
|
+
let dstStat;
|
|
62664
|
+
try {
|
|
62665
|
+
dstStat = fs11.lstatSync(dst);
|
|
62666
|
+
} catch {
|
|
62667
|
+
}
|
|
62668
|
+
if (dstStat) {
|
|
62669
|
+
if (dstStat.isDirectory()) throw new Error("target is a directory");
|
|
62670
|
+
const conflict = freeConflictName(dst);
|
|
62671
|
+
fs11.renameSync(dst, conflict);
|
|
62672
|
+
undo.push(() => fs11.renameSync(conflict, dst));
|
|
62673
|
+
}
|
|
62674
|
+
fs11.renameSync(src, dst);
|
|
62675
|
+
undo.push(() => fs11.renameSync(dst, src));
|
|
62676
|
+
};
|
|
62677
|
+
const preserveAsConflict = (src, name) => {
|
|
62678
|
+
const conflict = freeConflictName(path14.join(realHome, name));
|
|
62679
|
+
fs11.renameSync(src, conflict);
|
|
62680
|
+
undo.push(() => fs11.renameSync(conflict, src));
|
|
62681
|
+
};
|
|
62400
62682
|
try {
|
|
62401
62683
|
for (const m2 of members) {
|
|
62402
|
-
const
|
|
62403
|
-
const
|
|
62404
|
-
|
|
62405
|
-
|
|
62406
|
-
|
|
62407
|
-
}
|
|
62408
|
-
|
|
62409
|
-
|
|
62410
|
-
|
|
62411
|
-
|
|
62412
|
-
}
|
|
62413
|
-
const srcStat = fs11.lstatSync(src);
|
|
62414
|
-
if (dstStat && dstStat.mtimeMs >= srcStat.mtimeMs) {
|
|
62415
|
-
try {
|
|
62416
|
-
fs11.renameSync(src, `${dst}.bili-conflict`);
|
|
62417
|
-
} catch {
|
|
62418
|
-
rollback();
|
|
62419
|
-
return false;
|
|
62420
|
-
}
|
|
62421
|
-
undo.push(() => fs11.renameSync(`${dst}.bili-conflict`, src));
|
|
62422
|
-
continue;
|
|
62423
|
-
}
|
|
62424
|
-
if (dstStat) {
|
|
62425
|
-
try {
|
|
62426
|
-
fs11.renameSync(dst, `${dst}.bili-conflict`);
|
|
62427
|
-
} catch {
|
|
62428
|
-
rollback();
|
|
62429
|
-
return false;
|
|
62430
|
-
}
|
|
62431
|
-
undo.push(() => fs11.renameSync(`${dst}.bili-conflict`, dst));
|
|
62432
|
-
}
|
|
62433
|
-
try {
|
|
62434
|
-
fs11.renameSync(src, dst);
|
|
62435
|
-
} catch {
|
|
62436
|
-
rollback();
|
|
62437
|
-
return false;
|
|
62684
|
+
const o = statFile(overlay, m2);
|
|
62685
|
+
const r = statFile(realHome, m2);
|
|
62686
|
+
if (winner === "overlay") {
|
|
62687
|
+
if (o) movePreserving(path14.join(overlay, m2), path14.join(realHome, m2));
|
|
62688
|
+
else if (r) preserveAsConflict(path14.join(realHome, m2), m2);
|
|
62689
|
+
} else if (winner === "real") {
|
|
62690
|
+
if (o) preserveAsConflict(path14.join(overlay, m2), m2);
|
|
62691
|
+
} else {
|
|
62692
|
+
if (o) preserveAsConflict(path14.join(overlay, m2), m2);
|
|
62693
|
+
else if (r) preserveAsConflict(path14.join(realHome, m2), m2);
|
|
62438
62694
|
}
|
|
62439
|
-
undo.push(() => fs11.renameSync(dst, src));
|
|
62440
62695
|
}
|
|
62441
62696
|
return true;
|
|
62442
62697
|
} catch {
|
|
@@ -62445,6 +62700,8 @@ function mergeSqliteSet(overlay, realHome, base) {
|
|
|
62445
62700
|
}
|
|
62446
62701
|
}
|
|
62447
62702
|
function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
62703
|
+
const generatedFiles = new Set(Array.isArray(generatedFile) ? generatedFile : [generatedFile]);
|
|
62704
|
+
const isGeneratedDraft = (name) => [...generatedFiles].some((g2) => name.startsWith(`.${g2}.`) && name.endsWith(".tmp"));
|
|
62448
62705
|
try {
|
|
62449
62706
|
fs11.mkdirSync(overlay, { recursive: true });
|
|
62450
62707
|
} catch {
|
|
@@ -62475,7 +62732,7 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
|
62475
62732
|
}
|
|
62476
62733
|
const dbSets = [];
|
|
62477
62734
|
for (const entry of overlayEntries) {
|
|
62478
|
-
if (!entry.endsWith(".db") || entry
|
|
62735
|
+
if (!entry.endsWith(".db") || generatedFiles.has(entry)) continue;
|
|
62479
62736
|
const members = sqliteSetMembers(entry);
|
|
62480
62737
|
if (!members.some((m2) => m2 !== entry && overlayEntries.includes(m2))) continue;
|
|
62481
62738
|
let mainSt;
|
|
@@ -62493,9 +62750,9 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
|
62493
62750
|
}
|
|
62494
62751
|
}
|
|
62495
62752
|
for (const entry of overlayEntries) {
|
|
62496
|
-
if (entry
|
|
62753
|
+
if (generatedFiles.has(entry)) continue;
|
|
62497
62754
|
const overlayPath = path14.join(overlay, entry);
|
|
62498
|
-
if (
|
|
62755
|
+
if (isGeneratedDraft(entry)) {
|
|
62499
62756
|
try {
|
|
62500
62757
|
fs11.unlinkSync(overlayPath);
|
|
62501
62758
|
} catch {
|
|
@@ -62529,7 +62786,7 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
|
62529
62786
|
fs11.unlinkSync(overlayPath);
|
|
62530
62787
|
} catch {
|
|
62531
62788
|
}
|
|
62532
|
-
} else if (mergeOverlayEntry(overlayPath, realPath,
|
|
62789
|
+
} else if (mergeOverlayEntry(overlayPath, realPath, generatedFiles)) {
|
|
62533
62790
|
try {
|
|
62534
62791
|
fs11.rmSync(overlayPath, { recursive: true, force: true });
|
|
62535
62792
|
} catch {
|
|
@@ -62551,7 +62808,7 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
|
62551
62808
|
let total = 0;
|
|
62552
62809
|
const linkFailures = [];
|
|
62553
62810
|
for (const entry of realEntries) {
|
|
62554
|
-
if (entry
|
|
62811
|
+
if (generatedFiles.has(entry)) continue;
|
|
62555
62812
|
total += 1;
|
|
62556
62813
|
const overlayPath = path14.join(overlay, entry);
|
|
62557
62814
|
let present = false;
|
|
@@ -62585,7 +62842,7 @@ function refreshOverlayHome(realHome, overlay, generatedFile) {
|
|
|
62585
62842
|
}
|
|
62586
62843
|
return true;
|
|
62587
62844
|
}
|
|
62588
|
-
function mergeOverlayEntry(src, dst,
|
|
62845
|
+
function mergeOverlayEntry(src, dst, excludedNames) {
|
|
62589
62846
|
let st2;
|
|
62590
62847
|
try {
|
|
62591
62848
|
st2 = fs11.lstatSync(src);
|
|
@@ -62600,7 +62857,7 @@ function mergeOverlayEntry(src, dst, excludedName) {
|
|
|
62600
62857
|
if (st2.isDirectory()) {
|
|
62601
62858
|
if (dstStat && !dstStat.isDirectory()) {
|
|
62602
62859
|
try {
|
|
62603
|
-
fs11.renameSync(dst,
|
|
62860
|
+
fs11.renameSync(dst, freeConflictName(dst));
|
|
62604
62861
|
dstStat = void 0;
|
|
62605
62862
|
} catch {
|
|
62606
62863
|
return false;
|
|
@@ -62619,14 +62876,14 @@ function mergeOverlayEntry(src, dst, excludedName) {
|
|
|
62619
62876
|
}
|
|
62620
62877
|
let ok = true;
|
|
62621
62878
|
for (const entry of entries) {
|
|
62622
|
-
if (
|
|
62623
|
-
if (!mergeOverlayEntry(path14.join(src, entry), path14.join(dst, entry),
|
|
62879
|
+
if (excludedNames?.has(entry)) continue;
|
|
62880
|
+
if (!mergeOverlayEntry(path14.join(src, entry), path14.join(dst, entry), excludedNames)) ok = false;
|
|
62624
62881
|
}
|
|
62625
62882
|
return ok;
|
|
62626
62883
|
}
|
|
62627
62884
|
if (dstStat && dstStat.isDirectory()) {
|
|
62628
62885
|
try {
|
|
62629
|
-
fs11.renameSync(src,
|
|
62886
|
+
fs11.renameSync(src, freeConflictName(dst));
|
|
62630
62887
|
return true;
|
|
62631
62888
|
} catch {
|
|
62632
62889
|
return false;
|
|
@@ -62649,7 +62906,7 @@ function mergeOverlayEntry(src, dst, excludedName) {
|
|
|
62649
62906
|
}
|
|
62650
62907
|
if (dstStat && dstStat.mtimeMs >= st2.mtimeMs) {
|
|
62651
62908
|
try {
|
|
62652
|
-
fs11.renameSync(src,
|
|
62909
|
+
fs11.renameSync(src, freeConflictName(dst));
|
|
62653
62910
|
return true;
|
|
62654
62911
|
} catch {
|
|
62655
62912
|
return false;
|
|
@@ -62657,7 +62914,7 @@ function mergeOverlayEntry(src, dst, excludedName) {
|
|
|
62657
62914
|
}
|
|
62658
62915
|
if (dstStat) {
|
|
62659
62916
|
try {
|
|
62660
|
-
fs11.renameSync(dst,
|
|
62917
|
+
fs11.renameSync(dst, freeConflictName(dst));
|
|
62661
62918
|
} catch {
|
|
62662
62919
|
return false;
|
|
62663
62920
|
}
|
|
@@ -62692,45 +62949,58 @@ function writeOverlayFileAtomic(overlay, fileName, contents) {
|
|
|
62692
62949
|
}
|
|
62693
62950
|
}
|
|
62694
62951
|
}
|
|
62695
|
-
function
|
|
62696
|
-
|
|
62697
|
-
const modelsPath = path14.join(piHome, "models.json");
|
|
62698
|
-
let txt;
|
|
62952
|
+
function writePiCompactionDisabledSettings(piHome, overlay) {
|
|
62953
|
+
let settings = {};
|
|
62699
62954
|
try {
|
|
62700
|
-
|
|
62955
|
+
const parsed = JSON.parse(fs11.readFileSync(path14.join(piHome, "settings.json"), "utf8"));
|
|
62956
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
62957
|
+
settings = parsed;
|
|
62958
|
+
}
|
|
62701
62959
|
} catch {
|
|
62702
|
-
return void 0;
|
|
62703
62960
|
}
|
|
62704
|
-
|
|
62961
|
+
const compactionRaw = settings.compaction;
|
|
62962
|
+
const compaction = compactionRaw && typeof compactionRaw === "object" && !Array.isArray(compactionRaw) ? { ...compactionRaw } : {};
|
|
62963
|
+
compaction.enabled = false;
|
|
62964
|
+
settings.compaction = compaction;
|
|
62965
|
+
writeOverlayFileAtomic(overlay, "settings.json", JSON.stringify(settings, null, 2));
|
|
62966
|
+
}
|
|
62967
|
+
function preparePiHttpRewrite(piHome, origin, httpRewrites, httpsRewrites) {
|
|
62968
|
+
if (!fs11.existsSync(piHome)) return void 0;
|
|
62969
|
+
const overlay = `${piHome}-bili`;
|
|
62970
|
+
const generated = ["settings.json"];
|
|
62971
|
+
let modelsRoot;
|
|
62705
62972
|
try {
|
|
62706
|
-
parsed = JSON.parse(
|
|
62973
|
+
const parsed = JSON.parse(fs11.readFileSync(path14.join(piHome, "models.json"), "utf8"));
|
|
62974
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
62975
|
+
modelsRoot = parsed;
|
|
62976
|
+
generated.push("models.json");
|
|
62977
|
+
}
|
|
62707
62978
|
} catch {
|
|
62708
|
-
return void 0;
|
|
62709
62979
|
}
|
|
62710
|
-
if (!
|
|
62711
|
-
|
|
62712
|
-
|
|
62713
|
-
|
|
62714
|
-
|
|
62715
|
-
|
|
62716
|
-
|
|
62717
|
-
|
|
62718
|
-
|
|
62719
|
-
|
|
62720
|
-
|
|
62980
|
+
if (!refreshOverlayHome(piHome, overlay, generated)) return void 0;
|
|
62981
|
+
if (modelsRoot) {
|
|
62982
|
+
const providersVal = modelsRoot.providers;
|
|
62983
|
+
if (providersVal && typeof providersVal === "object" && !Array.isArray(providersVal)) {
|
|
62984
|
+
const providers = providersVal;
|
|
62985
|
+
for (const r of httpRewrites) {
|
|
62986
|
+
const prov = providers[r.key];
|
|
62987
|
+
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
62988
|
+
const p2 = prov;
|
|
62989
|
+
const existing = typeof p2.baseUrl === "string" ? p2.baseUrl : r.realUpstream;
|
|
62990
|
+
p2.baseUrl = wrapUpstream(origin, unwrapUpstream2(existing));
|
|
62991
|
+
}
|
|
62721
62992
|
}
|
|
62722
|
-
|
|
62723
|
-
|
|
62724
|
-
|
|
62725
|
-
|
|
62726
|
-
|
|
62727
|
-
|
|
62993
|
+
for (const r of httpsRewrites) {
|
|
62994
|
+
const prov = providers[r.key];
|
|
62995
|
+
if (prov && typeof prov === "object" && !Array.isArray(prov)) {
|
|
62996
|
+
const p2 = prov;
|
|
62997
|
+
p2.baseUrl = r.realUpstream;
|
|
62998
|
+
}
|
|
62728
62999
|
}
|
|
62729
63000
|
}
|
|
63001
|
+
writeOverlayFileAtomic(overlay, "models.json", JSON.stringify(modelsRoot));
|
|
62730
63002
|
}
|
|
62731
|
-
|
|
62732
|
-
if (!refreshOverlayHome(piHome, overlay, "models.json")) return void 0;
|
|
62733
|
-
writeOverlayFileAtomic(overlay, "models.json", JSON.stringify(root));
|
|
63003
|
+
writePiCompactionDisabledSettings(piHome, overlay);
|
|
62734
63004
|
return overlay;
|
|
62735
63005
|
}
|
|
62736
63006
|
function atomicWriteTextFile(filePath, contents) {
|
|
@@ -62781,55 +63051,145 @@ function unpackDeadProxyUrlsInFile(filePath, livePorts) {
|
|
|
62781
63051
|
}
|
|
62782
63052
|
return changed;
|
|
62783
63053
|
}
|
|
63054
|
+
function mergeOmpCompactionDisabledYaml(text) {
|
|
63055
|
+
const lines = text.split(/\r?\n/);
|
|
63056
|
+
let compactionLine = -1;
|
|
63057
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63058
|
+
const rawLine = lines[i];
|
|
63059
|
+
const trimmed = rawLine.trim();
|
|
63060
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63061
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63062
|
+
if (indent === 0 && /^compaction:\s*(#.*)?$/.test(trimmed)) {
|
|
63063
|
+
compactionLine = i;
|
|
63064
|
+
break;
|
|
63065
|
+
}
|
|
63066
|
+
}
|
|
63067
|
+
if (compactionLine === -1) {
|
|
63068
|
+
const base = text === "" || text.endsWith("\n") ? text : `${text}
|
|
63069
|
+
`;
|
|
63070
|
+
return `${base}compaction:
|
|
63071
|
+
enabled: false
|
|
63072
|
+
`;
|
|
63073
|
+
}
|
|
63074
|
+
for (let i = compactionLine + 1; i < lines.length; i++) {
|
|
63075
|
+
const rawLine = lines[i];
|
|
63076
|
+
const trimmed = rawLine.trim();
|
|
63077
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63078
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63079
|
+
if (indent === 0) break;
|
|
63080
|
+
if (/^enabled:/.test(trimmed)) {
|
|
63081
|
+
const leading = rawLine.slice(0, rawLine.length - rawLine.trimStart().length);
|
|
63082
|
+
const commentMatch = /\s+#.*$/.exec(rawLine);
|
|
63083
|
+
const comment = commentMatch ? commentMatch[0] : "";
|
|
63084
|
+
lines[i] = `${leading}enabled: false${comment}`;
|
|
63085
|
+
return lines.join("\n");
|
|
63086
|
+
}
|
|
63087
|
+
}
|
|
63088
|
+
let childIndent = 2;
|
|
63089
|
+
for (let i = compactionLine + 1; i < lines.length; i++) {
|
|
63090
|
+
const rawLine = lines[i];
|
|
63091
|
+
const trimmed = rawLine.trim();
|
|
63092
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63093
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63094
|
+
if (indent === 0) break;
|
|
63095
|
+
childIndent = indent;
|
|
63096
|
+
break;
|
|
63097
|
+
}
|
|
63098
|
+
lines.splice(compactionLine + 1, 0, `${" ".repeat(childIndent)}enabled: false`);
|
|
63099
|
+
return lines.join("\n");
|
|
63100
|
+
}
|
|
63101
|
+
function writeOmpCompactionDisabledConfig(ompHome, overlay) {
|
|
63102
|
+
let base;
|
|
63103
|
+
let baseIsJson = false;
|
|
63104
|
+
for (const name of ["config.yml", "config.yaml"]) {
|
|
63105
|
+
try {
|
|
63106
|
+
base = fs11.readFileSync(path14.join(ompHome, name), "utf8");
|
|
63107
|
+
break;
|
|
63108
|
+
} catch {
|
|
63109
|
+
}
|
|
63110
|
+
}
|
|
63111
|
+
if (base === void 0) {
|
|
63112
|
+
try {
|
|
63113
|
+
base = fs11.readFileSync(path14.join(ompHome, "settings.json"), "utf8");
|
|
63114
|
+
baseIsJson = true;
|
|
63115
|
+
} catch {
|
|
63116
|
+
}
|
|
63117
|
+
}
|
|
63118
|
+
let merged;
|
|
63119
|
+
if (base === void 0) {
|
|
63120
|
+
merged = "compaction:\n enabled: false\n";
|
|
63121
|
+
} else if (baseIsJson) {
|
|
63122
|
+
let settings = {};
|
|
63123
|
+
try {
|
|
63124
|
+
const parsed = JSON.parse(base);
|
|
63125
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
63126
|
+
settings = parsed;
|
|
63127
|
+
}
|
|
63128
|
+
} catch {
|
|
63129
|
+
}
|
|
63130
|
+
const compactionRaw = settings.compaction;
|
|
63131
|
+
const compaction = compactionRaw && typeof compactionRaw === "object" && !Array.isArray(compactionRaw) ? { ...compactionRaw } : {};
|
|
63132
|
+
compaction.enabled = false;
|
|
63133
|
+
settings.compaction = compaction;
|
|
63134
|
+
merged = JSON.stringify(settings, null, 2);
|
|
63135
|
+
} else {
|
|
63136
|
+
merged = mergeOmpCompactionDisabledYaml(base);
|
|
63137
|
+
}
|
|
63138
|
+
writeOverlayFileAtomic(overlay, "config.yml", merged);
|
|
63139
|
+
}
|
|
62784
63140
|
function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
|
|
63141
|
+
if (!fs11.existsSync(ompHome)) return void 0;
|
|
63142
|
+
const overlay = `${ompHome}-bili`;
|
|
63143
|
+
const generated = ["config.yml"];
|
|
62785
63144
|
const modelsPath = path14.join(ompHome, "models.yml");
|
|
62786
63145
|
const unpacked = unpackDeadProxyUrlsInFile(modelsPath, liveProxyPorts());
|
|
62787
63146
|
if (unpacked > 0) {
|
|
62788
63147
|
console.error(`bili: unpacked ${unpacked} dead proxy URL(s) from the real ${modelsPath}`);
|
|
62789
63148
|
}
|
|
62790
|
-
|
|
62791
|
-
let txt;
|
|
63149
|
+
let modelsText;
|
|
62792
63150
|
try {
|
|
62793
|
-
|
|
63151
|
+
modelsText = fs11.readFileSync(modelsPath, "utf8");
|
|
63152
|
+
generated.push("models.yml");
|
|
62794
63153
|
} catch {
|
|
62795
|
-
return void 0;
|
|
62796
63154
|
}
|
|
62797
|
-
|
|
62798
|
-
|
|
62799
|
-
|
|
62800
|
-
|
|
62801
|
-
|
|
62802
|
-
|
|
62803
|
-
|
|
62804
|
-
|
|
62805
|
-
|
|
62806
|
-
|
|
62807
|
-
|
|
62808
|
-
|
|
62809
|
-
|
|
62810
|
-
|
|
62811
|
-
|
|
62812
|
-
|
|
62813
|
-
|
|
62814
|
-
|
|
62815
|
-
|
|
62816
|
-
|
|
62817
|
-
|
|
62818
|
-
|
|
62819
|
-
if (
|
|
62820
|
-
const
|
|
62821
|
-
if (
|
|
62822
|
-
const
|
|
62823
|
-
|
|
62824
|
-
|
|
62825
|
-
|
|
63155
|
+
if (!refreshOverlayHome(ompHome, overlay, generated)) return void 0;
|
|
63156
|
+
if (modelsText !== void 0) {
|
|
63157
|
+
const httpMap = new Map(httpRewrites.map((r) => [r.key, wrapUpstream(origin, r.realUpstream)]));
|
|
63158
|
+
const httpsMap = new Map(httpsRewrites.map((r) => [r.key, r.realUpstream]));
|
|
63159
|
+
const lines = modelsText.split(/\r?\n/);
|
|
63160
|
+
let providersIndent = -1;
|
|
63161
|
+
let providerIndent = -1;
|
|
63162
|
+
let currentProvider = null;
|
|
63163
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63164
|
+
const rawLine = lines[i];
|
|
63165
|
+
const trimmed = rawLine.trim();
|
|
63166
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
63167
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
63168
|
+
if (providersIndent === -1) {
|
|
63169
|
+
if (/^providers:\s*(#.*)?$/.test(trimmed)) providersIndent = indent;
|
|
63170
|
+
continue;
|
|
63171
|
+
}
|
|
63172
|
+
if (indent <= providersIndent) break;
|
|
63173
|
+
if (providerIndent === -1) providerIndent = indent;
|
|
63174
|
+
if (indent === providerIndent) {
|
|
63175
|
+
const m2 = /^([A-Za-z0-9_.-]+):/.exec(trimmed);
|
|
63176
|
+
currentProvider = m2 ? m2[1] : null;
|
|
63177
|
+
} else if (indent > providerIndent && currentProvider) {
|
|
63178
|
+
const baseMatch = /^(baseUrl:\s*)(\S+)/.exec(trimmed);
|
|
63179
|
+
if (baseMatch) {
|
|
63180
|
+
const target = httpMap.get(currentProvider) ?? httpsMap.get(currentProvider);
|
|
63181
|
+
if (target) {
|
|
63182
|
+
const leading = rawLine.slice(0, rawLine.length - rawLine.trimStart().length);
|
|
63183
|
+
const commentMatch = /\s+#.*$/.exec(rawLine);
|
|
63184
|
+
const comment = commentMatch ? commentMatch[0] : "";
|
|
63185
|
+
lines[i] = `${leading}baseUrl: ${target}${comment}`;
|
|
63186
|
+
}
|
|
62826
63187
|
}
|
|
62827
63188
|
}
|
|
62828
63189
|
}
|
|
63190
|
+
writeOverlayFileAtomic(overlay, "models.yml", lines.join("\n"));
|
|
62829
63191
|
}
|
|
62830
|
-
|
|
62831
|
-
if (!refreshOverlayHome(ompHome, overlay, "models.yml")) return void 0;
|
|
62832
|
-
writeOverlayFileAtomic(overlay, "models.yml", lines.join("\n"));
|
|
63192
|
+
writeOmpCompactionDisabledConfig(ompHome, overlay);
|
|
62833
63193
|
return overlay;
|
|
62834
63194
|
}
|
|
62835
63195
|
function prepareHermesHome(hermesHome, origin, rewrites) {
|