billion-context 0.1.85 → 0.1.86-pr.561.380
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -69
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -47078,7 +47078,7 @@ function caDir() {
|
|
|
47078
47078
|
}
|
|
47079
47079
|
|
|
47080
47080
|
// src/logger.ts
|
|
47081
|
-
import { createWriteStream, fstatSync, mkdirSync, statSync, renameSync } from "fs";
|
|
47081
|
+
import { createWriteStream, fstatSync, mkdirSync, statSync, renameSync, unlinkSync } from "fs";
|
|
47082
47082
|
import path2 from "path";
|
|
47083
47083
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
47084
47084
|
var stream;
|
|
@@ -47094,6 +47094,10 @@ function openStream(file) {
|
|
|
47094
47094
|
existingSize = statSync(file).size;
|
|
47095
47095
|
if (existingSize >= MAX_BYTES) {
|
|
47096
47096
|
try {
|
|
47097
|
+
try {
|
|
47098
|
+
unlinkSync(file + ".old");
|
|
47099
|
+
} catch {
|
|
47100
|
+
}
|
|
47097
47101
|
renameSync(file, file + ".old");
|
|
47098
47102
|
existingSize = 0;
|
|
47099
47103
|
} catch {
|
|
@@ -47738,6 +47742,11 @@ function loadRoutes(env = process.env) {
|
|
|
47738
47742
|
}
|
|
47739
47743
|
return routes;
|
|
47740
47744
|
}
|
|
47745
|
+
function passthroughState(env) {
|
|
47746
|
+
const filePassthrough = loadConfigFile().passthrough === true;
|
|
47747
|
+
if (env.ACP_PASSTHROUGH !== void 0) return { enabled: env.ACP_PASSTHROUGH === "1", source: "env" };
|
|
47748
|
+
return { enabled: filePassthrough, source: filePassthrough ? "file" : null };
|
|
47749
|
+
}
|
|
47741
47750
|
function loadOptions(env = process.env) {
|
|
47742
47751
|
const fileConfig = loadConfigFile();
|
|
47743
47752
|
const port = parseInt(env.ACP_PORT ?? env.PORT ?? `${fileConfig.port ?? 8787}`, 10);
|
|
@@ -47748,6 +47757,7 @@ function loadOptions(env = process.env) {
|
|
|
47748
47757
|
const host = rawHost === "localhost" ? "127.0.0.1" : rawHost;
|
|
47749
47758
|
const upstream = (env.ACP_UPSTREAM ?? fileConfig.upstream ?? "https://api.anthropic.com").replace(/\/$/, "");
|
|
47750
47759
|
const routes = loadRoutes(env);
|
|
47760
|
+
const passthrough = passthroughState(env);
|
|
47751
47761
|
const modelContextLimit = parseInt(env.ACP_MODEL_CONTEXT_LIMIT ?? `${fileConfig.modelContextLimit ?? 2e5}`, 10);
|
|
47752
47762
|
const biliProxy = nonEmpty(env.BILI_UPSTREAM_PROXY);
|
|
47753
47763
|
const webProxy = nonEmpty(fileConfig.upstreamProxy);
|
|
@@ -47802,7 +47812,8 @@ function loadOptions(env = process.env) {
|
|
|
47802
47812
|
log: env.ACP_LOG !== "0" && fileConfig.log !== false,
|
|
47803
47813
|
debug: (env.ACP_DEBUG ?? (fileConfig.debug ? "1" : "0")) === "1",
|
|
47804
47814
|
dumpSse: env.ACP_DUMP_SSE || fileConfig.dumpSse || void 0,
|
|
47805
|
-
passthrough:
|
|
47815
|
+
passthrough: passthrough.enabled,
|
|
47816
|
+
passthroughSource: passthrough.source,
|
|
47806
47817
|
autoUpdate: (env.ACP_AUTO_UPDATE ?? (fileConfig.autoUpdate === false ? "0" : "1")) !== "0",
|
|
47807
47818
|
logFile: env.ACP_LOG_FILE !== void 0 ? env.ACP_LOG_FILE || void 0 : fileConfig.logFile,
|
|
47808
47819
|
mitm: {
|
|
@@ -49475,15 +49486,11 @@ var StateStore = class {
|
|
|
49475
49486
|
}
|
|
49476
49487
|
const file = this.resolvePath(id, payload);
|
|
49477
49488
|
const data = JSON.stringify(this.envelope(id, payload));
|
|
49478
|
-
try {
|
|
49479
|
-
fs.mkdirSync(path4.dirname(file), { recursive: true });
|
|
49480
|
-
} catch (e) {
|
|
49481
|
-
this.log("warn", `[persist] could not create dir ${path4.dirname(file)}: ${errText(e)}`);
|
|
49482
|
-
}
|
|
49483
49489
|
let lastErr;
|
|
49484
49490
|
for (let attempt = 0; attempt < this.retryAttempts; attempt++) {
|
|
49485
49491
|
const tmp = this.tempPath(file);
|
|
49486
49492
|
try {
|
|
49493
|
+
fs.mkdirSync(path4.dirname(file), { recursive: true });
|
|
49487
49494
|
fs.writeFileSync(tmp, data, "utf8");
|
|
49488
49495
|
fs.renameSync(tmp, file);
|
|
49489
49496
|
lastErr = void 0;
|
|
@@ -49494,9 +49501,7 @@ var StateStore = class {
|
|
|
49494
49501
|
fs.unlinkSync(tmp);
|
|
49495
49502
|
} catch {
|
|
49496
49503
|
}
|
|
49497
|
-
|
|
49498
|
-
if (code !== "EPERM" && code !== "EBUSY" && code !== "EACCES") break;
|
|
49499
|
-
if (attempt === this.retryAttempts - 1) break;
|
|
49504
|
+
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
49500
49505
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, this.backoffMs(attempt));
|
|
49501
49506
|
}
|
|
49502
49507
|
}
|
|
@@ -49506,14 +49511,19 @@ var StateStore = class {
|
|
|
49506
49511
|
this.removeSpillSync(file);
|
|
49507
49512
|
return true;
|
|
49508
49513
|
}
|
|
49514
|
+
const spill = this.spillPathFor(file);
|
|
49509
49515
|
let spillPath = null;
|
|
49510
|
-
|
|
49511
|
-
|
|
49512
|
-
|
|
49513
|
-
|
|
49514
|
-
|
|
49515
|
-
|
|
49516
|
+
for (let attempt = 0; attempt < this.retryAttempts && spillPath === null; attempt++) {
|
|
49517
|
+
try {
|
|
49518
|
+
fs.mkdirSync(path4.dirname(spill), { recursive: true });
|
|
49519
|
+
fs.writeFileSync(spill, data, "utf8");
|
|
49520
|
+
spillPath = spill;
|
|
49521
|
+
} catch (e) {
|
|
49522
|
+
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
49523
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, this.backoffMs(attempt));
|
|
49524
|
+
}
|
|
49516
49525
|
}
|
|
49526
|
+
if (spillPath) this.discovered.set(id, spillPath);
|
|
49517
49527
|
this.recordFailure(id, lastErr, spillPath);
|
|
49518
49528
|
return spillPath !== null;
|
|
49519
49529
|
}
|
|
@@ -49617,33 +49627,45 @@ var StateStore = class {
|
|
|
49617
49627
|
throw e;
|
|
49618
49628
|
}
|
|
49619
49629
|
const file = this.resolvePath(id, payload);
|
|
49620
|
-
|
|
49621
|
-
|
|
49622
|
-
|
|
49623
|
-
|
|
49630
|
+
const data = JSON.stringify(this.envelope(id, payload));
|
|
49631
|
+
let lastErr;
|
|
49632
|
+
for (let attempt = 0; attempt < this.retryAttempts; attempt++) {
|
|
49633
|
+
const tmp = this.tempPath(file);
|
|
49634
|
+
try {
|
|
49635
|
+
await fsp.mkdir(path4.dirname(file), { recursive: true });
|
|
49636
|
+
await fsp.writeFile(tmp, data, "utf8");
|
|
49637
|
+
await fsp.rename(tmp, file);
|
|
49638
|
+
this.discovered.set(id, file);
|
|
49639
|
+
this.clearFailure(id);
|
|
49640
|
+
await this.removeSpill(file);
|
|
49641
|
+
return;
|
|
49642
|
+
} catch (e) {
|
|
49643
|
+
lastErr = e;
|
|
49644
|
+
await fsp.unlink(tmp).catch(() => {
|
|
49645
|
+
});
|
|
49646
|
+
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
49647
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
49648
|
+
setTimeout(resolve, this.backoffMs(attempt));
|
|
49649
|
+
await promise;
|
|
49650
|
+
}
|
|
49624
49651
|
}
|
|
49625
|
-
const
|
|
49626
|
-
|
|
49627
|
-
|
|
49628
|
-
await fsp.writeFile(tmp, JSON.stringify(env), "utf8");
|
|
49629
|
-
await this.renameWithRetry(tmp, file);
|
|
49630
|
-
this.discovered.set(id, file);
|
|
49631
|
-
this.clearFailure(id);
|
|
49632
|
-
await this.removeSpill(file);
|
|
49633
|
-
} catch (e) {
|
|
49634
|
-
await fsp.unlink(tmp).catch(() => {
|
|
49635
|
-
});
|
|
49636
|
-
let spillPath = null;
|
|
49652
|
+
const spill = this.spillPathFor(file);
|
|
49653
|
+
let spillPath = null;
|
|
49654
|
+
for (let attempt = 0; attempt < this.retryAttempts && spillPath === null; attempt++) {
|
|
49637
49655
|
try {
|
|
49638
|
-
|
|
49639
|
-
await fsp.writeFile(spill,
|
|
49656
|
+
await fsp.mkdir(path4.dirname(spill), { recursive: true });
|
|
49657
|
+
await fsp.writeFile(spill, data, "utf8");
|
|
49640
49658
|
spillPath = spill;
|
|
49641
|
-
|
|
49642
|
-
|
|
49659
|
+
} catch (e) {
|
|
49660
|
+
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
49661
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
49662
|
+
setTimeout(resolve, this.backoffMs(attempt));
|
|
49663
|
+
await promise;
|
|
49643
49664
|
}
|
|
49644
|
-
this.recordFailure(id, e, spillPath);
|
|
49645
|
-
throw e;
|
|
49646
49665
|
}
|
|
49666
|
+
if (spillPath) this.discovered.set(id, spillPath);
|
|
49667
|
+
this.recordFailure(id, lastErr, spillPath);
|
|
49668
|
+
throw lastErr;
|
|
49647
49669
|
}
|
|
49648
49670
|
envelope(id, payload) {
|
|
49649
49671
|
return { version: this.version, savedAt: Date.now(), id, payload };
|
|
@@ -49709,27 +49731,6 @@ var StateStore = class {
|
|
|
49709
49731
|
clearFailure(id) {
|
|
49710
49732
|
this.failCounts.delete(id);
|
|
49711
49733
|
}
|
|
49712
|
-
/** fs.rename with exponential-backoff retries on Windows transient locks
|
|
49713
|
-
* (EPERM/EBUSY/EACCES from AV scan, search indexer, SMB). Other errors
|
|
49714
|
-
* are real and rethrown immediately. */
|
|
49715
|
-
async renameWithRetry(src, dest) {
|
|
49716
|
-
let lastErr;
|
|
49717
|
-
for (let attempt = 0; attempt < this.retryAttempts; attempt++) {
|
|
49718
|
-
try {
|
|
49719
|
-
await fsp.rename(src, dest);
|
|
49720
|
-
return;
|
|
49721
|
-
} catch (e) {
|
|
49722
|
-
lastErr = e;
|
|
49723
|
-
const code = e.code;
|
|
49724
|
-
if (code !== "EPERM" && code !== "EBUSY" && code !== "EACCES") throw e;
|
|
49725
|
-
if (attempt === this.retryAttempts - 1) throw e;
|
|
49726
|
-
const { promise, resolve } = Promise.withResolvers();
|
|
49727
|
-
setTimeout(resolve, this.backoffMs(attempt));
|
|
49728
|
-
await promise;
|
|
49729
|
-
}
|
|
49730
|
-
}
|
|
49731
|
-
throw lastErr;
|
|
49732
|
-
}
|
|
49733
49734
|
/** Parse + validate one file. Corrupt or invalid records return null
|
|
49734
49735
|
* (logged) instead of throwing — load paths must never block boot. */
|
|
49735
49736
|
readEnvelope(file) {
|
|
@@ -49805,6 +49806,10 @@ function isEnvelopeLike(value) {
|
|
|
49805
49806
|
function flatFileNameFor(id) {
|
|
49806
49807
|
return createHash2("sha256").update(id, "utf8").digest("hex").slice(0, 24) + ".json";
|
|
49807
49808
|
}
|
|
49809
|
+
function isTransientFsError(e) {
|
|
49810
|
+
const code = e.code;
|
|
49811
|
+
return code === "EPERM" || code === "EBUSY" || code === "EACCES" || code === "ENOENT" || code === "ENOTDIR";
|
|
49812
|
+
}
|
|
49808
49813
|
function errText(e) {
|
|
49809
49814
|
return e instanceof Error ? e.message : String(e);
|
|
49810
49815
|
}
|
|
@@ -50353,7 +50358,7 @@ function withStagedCompressGuidance(text) {
|
|
|
50353
50358
|
}
|
|
50354
50359
|
|
|
50355
50360
|
// src/decompress-shared.ts
|
|
50356
|
-
import { mkdirSync as mkdirSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
50361
|
+
import { mkdirSync as mkdirSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
50357
50362
|
import { dirname as dirname2, join as join2 } from "path";
|
|
50358
50363
|
import { tmpdir } from "os";
|
|
50359
50364
|
var trackedTempFiles = [];
|
|
@@ -50369,7 +50374,7 @@ function reapTempFiles() {
|
|
|
50369
50374
|
const oldest = trackedTempFiles.shift();
|
|
50370
50375
|
if (!oldest) break;
|
|
50371
50376
|
try {
|
|
50372
|
-
|
|
50377
|
+
unlinkSync2(oldest.path);
|
|
50373
50378
|
} catch {
|
|
50374
50379
|
}
|
|
50375
50380
|
}
|
|
@@ -50377,7 +50382,7 @@ function reapTempFiles() {
|
|
|
50377
50382
|
process.on("beforeExit", () => {
|
|
50378
50383
|
for (const f2 of trackedTempFiles) {
|
|
50379
50384
|
try {
|
|
50380
|
-
|
|
50385
|
+
unlinkSync2(f2.path);
|
|
50381
50386
|
} catch {
|
|
50382
50387
|
}
|
|
50383
50388
|
}
|
|
@@ -51262,7 +51267,7 @@ function busy(button,on,label){if(!button)return;if(on){button.dataset.label=but
|
|
|
51262
51267
|
async function json(url,options){const response=await fetch(url,options);const data=await response.json().catch(()=>({}));if(!response.ok)throw new Error(data.error||data.detail||("HTTP "+response.status));return data}
|
|
51263
51268
|
function showPage(name){document.querySelectorAll(".page").forEach((node)=>node.classList.toggle("active",node.id==="page-"+name));document.querySelectorAll(".nav button").forEach((node)=>node.classList.toggle("active",node.dataset.page===name));if(name==="sessions")loadSessions();if(name==="upstream"){loadUpstream();loadOverrides()}}
|
|
51264
51269
|
document.querySelectorAll(".nav button").forEach((button)=>button.addEventListener("click",()=>showPage(button.dataset.page)));
|
|
51265
|
-
async function loadConfig(){const data=await json("/__bili/config");if(data.parseError)toast(String(data.parseError),true);byId("providers-json").value=JSON.stringify(data.providers||{},null,2);byId("proxy-url").value=data.upstreamProxy||"";byId("compress-json").value=data.compress?JSON.stringify(data.compress,null,2):"";document.querySelectorAll('input[name="proxy-mode"]').forEach((input)=>input.checked=input.value===(data.upstreamProxyMode||"direct"));return data}
|
|
51270
|
+
async function loadConfig(){const data=await json("/__bili/config");if(data.parseError)toast(String(data.parseError),true);byId("providers-json").value=JSON.stringify(data.providers||{},null,2);byId("proxy-url").value=data.upstreamProxy||"";byId("compress-json").value=data.compress?JSON.stringify(data.compress,null,2):"";document.querySelectorAll('input[name="proxy-mode"]').forEach((input)=>input.checked=input.value===(data.upstreamProxyMode||"direct"));const pt=data.passthrough||{enabled:false};const banner=byId("passthrough-banner");if(banner){if(pt.enabled){banner.hidden=false;byId("passthrough-source").textContent=pt.source==="env"?"\u73AF\u5883\u53D8\u91CF ACP_PASSTHROUGH\uFF08\u6216 --passthrough \u53C2\u6570\uFF09":"\u914D\u7F6E\u6587\u4EF6 passthrough: true";const btn=byId("clear-passthrough");btn.disabled=pt.source==="env";btn.title=pt.source==="env"?"\u9700\u5148 unset ACP_PASSTHROUGH \u5E76\u91CD\u542F":""}else{banner.hidden=true}}return data}
|
|
51266
51271
|
async function loadUpstream(){try{const data=await json("/__bili/upstream");const labels={"provider":"Provider \u5355\u72EC\u4EE3\u7406","provider-direct":"Provider \u76F4\u8FDE","bili-env":"BILI_UPSTREAM_PROXY","web-manual":"Web \u624B\u52A8\u4EE3\u7406","config":"\u914D\u7F6E\u6587\u4EF6\u4EE3\u7406","HTTPS_PROXY":"HTTPS_PROXY","HTTP_PROXY":"HTTP_PROXY","ALL_PROXY":"ALL_PROXY","windows-system":"Windows \u7CFB\u7EDF\u4EE3\u7406","windows-bypass":"Windows \u7ED5\u8FC7\u5217\u8868","no-proxy":"NO_PROXY","direct":"\u76F4\u8FDE"};byId("upstream-source").textContent=labels[data.source]||data.source||"\u76F4\u8FDE";byId("upstream-effective").textContent=data.proxy||"direct";byId("upstream-pac").textContent=data.autoConfigUrl||"\u2014";const state=byId("upstream-state");state.className="status "+(data.connected===true?"ok":data.connected===false?"err":"");state.textContent=data.connected===true?"CONNECT \u6B63\u5E38":data.connected===false?(data.error||"\u8FDE\u63A5\u5931\u8D25"):"\u5C1A\u672A\u89C2\u5BDF\u5230\u4E0A\u6E38\u8FDE\u63A5"}catch(error){byId("upstream-state").textContent=String(error)}}
|
|
51267
51272
|
async function saveUpstream(){const button=byId("save-upstream");busy(button,true,"\u4FDD\u5B58\u4E2D\u2026");const mode=document.querySelector('input[name="proxy-mode"]:checked').value;try{await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({upstreamProxyMode:mode,upstreamProxy:byId("proxy-url").value.trim()||null})});toast("\u4E0A\u6E38\u8BBE\u7F6E\u5DF2\u70ED\u66F4\u65B0");await loadUpstream()}catch(error){toast(String(error),true)}finally{busy(button,false)}}
|
|
51268
51273
|
async function testUpstream(){const button=byId("test-upstream");busy(button,true,"\u6D4B\u8BD5\u4E2D\u2026");try{const data=await json("/__bili/upstream/test",{method:"POST"});toast("\u8FDE\u63A5\u6210\u529F\uFF0CHTTP "+data.status);await loadUpstream()}catch(error){toast(String(error),true);await loadUpstream()}finally{busy(button,false)}}
|
|
@@ -51272,7 +51277,9 @@ async function loadOverrides(){try{const data=await loadConfig();const providers
|
|
|
51272
51277
|
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)}}
|
|
51273
51278
|
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}}
|
|
51274
51279
|
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)}}
|
|
51275
|
-
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("
|
|
51280
|
+
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)}}));async function clearPassthrough(){const button=byId("clear-passthrough");busy(button,true,"\u5904\u7406\u4E2D\u2026");try{await json("/__bili/config",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({passthrough:null})});toast("\u5DF2\u6062\u590D\u538B\u7F29");await loadConfig()}catch(error){toast(String(error),true)}finally{busy(button,false)}}
|
|
51281
|
+
byId("clear-passthrough").addEventListener("click",clearPassthrough);
|
|
51282
|
+
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);
|
|
51276
51283
|
Promise.all([loadConfig(),loadUpstream()]).catch((error)=>toast(String(error),true));setInterval(()=>{if(byId("page-sessions").classList.contains("active"))loadSessions().catch(()=>{})},5000);
|
|
51277
51284
|
`;
|
|
51278
51285
|
|
|
@@ -51294,7 +51301,7 @@ function renderPage(origin, version2) {
|
|
|
51294
51301
|
const caReady = existsSync4(caPath);
|
|
51295
51302
|
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>
|
|
51296
51303
|
<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>
|
|
51297
|
-
<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>
|
|
51304
|
+
<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 id="passthrough-banner" class="notice" hidden>\u26A0\uFE0F <strong>Passthrough \u5DF2\u542F\u7528</strong>\uFF1A\u6240\u6709\u8BF7\u6C42\u539F\u6837\u8F6C\u53D1\uFF0C\u538B\u7F29\u5B8C\u5168\u5173\u95ED\uFF0C\u4E0D\u4F1A\u8282\u7701\u4EFB\u4F55 token\u3002\u6765\u6E90\uFF1A<span id="passthrough-source" class="mono"></span>\u3002 <button id="clear-passthrough" class="btn">\u6062\u590D\u538B\u7F29</button></div><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>
|
|
51298
51305
|
<section id="page-routing" class="page"><h1>\u5BA2\u6237\u7AEF\u63A5\u5165</h1><p class="lead">\u4E24\u7C7B\u63A5\u5165\uFF1AA. \u63A8\u8350\u63A5\u5165\u65B9\u5F0F\uFF08<span class="mono">/bili/</span> \u524D\u7F00\uFF0C\u96F6\u914D\u7F6E\uFF09\uFF1BB. \u8BC1\u4E66\u63A5\u5165\u65B9\u5F0F\uFF08MITM\uFF0C\u9700\u4FE1\u4EFB CA \u8BC1\u4E66\uFF09\u3002</p>
|
|
51299
51306
|
<h2 class="section-title">A. \u63A8\u8350\u63A5\u5165\u65B9\u5F0F\uFF08/bili/ \u524D\u7F00\uFF09</h2>
|
|
51300
51307
|
<p class="hint">\u5728\u5BA2\u6237\u7AEF\u914D\u7F6E\u91CC\u628A\u539F baseURL \u524D\u52A0\u4E0A <span class="mono">${origin}/bili/</span> \u5373\u53EF\uFF0C\u5176\u4F59\u4E0D\u53D8\u3002</p>
|
|
@@ -51313,7 +51320,7 @@ function renderPage(origin, version2) {
|
|
|
51313
51320
|
}
|
|
51314
51321
|
|
|
51315
51322
|
// src/web/api.ts
|
|
51316
|
-
import { closeSync, existsSync as existsSync5, fsyncSync, mkdirSync as mkdirSync5, openSync, renameSync as renameSync2, unlinkSync as
|
|
51323
|
+
import { closeSync, existsSync as existsSync5, fsyncSync, mkdirSync as mkdirSync5, openSync, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
51317
51324
|
import { dirname as dirname3 } from "path";
|
|
51318
51325
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
51319
51326
|
function readConfig() {
|
|
@@ -51352,7 +51359,7 @@ function atomicWriteConfig(config) {
|
|
|
51352
51359
|
} catch (error) {
|
|
51353
51360
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
51354
51361
|
try {
|
|
51355
|
-
|
|
51362
|
+
unlinkSync3(tempPath);
|
|
51356
51363
|
} catch {
|
|
51357
51364
|
}
|
|
51358
51365
|
throw error;
|
|
@@ -51370,6 +51377,7 @@ async function handleConfigGet(res) {
|
|
|
51370
51377
|
upstreamProxy: upstream.proxy ?? null,
|
|
51371
51378
|
upstreamProxyMode: upstream.mode,
|
|
51372
51379
|
compress: config.compress ?? null,
|
|
51380
|
+
passthrough: passthroughState(process.env),
|
|
51373
51381
|
...parseError ? { parseError } : {}
|
|
51374
51382
|
}, null, 2));
|
|
51375
51383
|
}
|
|
@@ -51383,7 +51391,8 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
|
|
|
51383
51391
|
const hasProxy = Object.prototype.hasOwnProperty.call(body, "upstreamProxy");
|
|
51384
51392
|
const hasMode = Object.prototype.hasOwnProperty.call(body, "upstreamProxyMode");
|
|
51385
51393
|
const hasCompress = Object.prototype.hasOwnProperty.call(body, "compress");
|
|
51386
|
-
|
|
51394
|
+
const hasPassthrough = Object.prototype.hasOwnProperty.call(body, "passthrough");
|
|
51395
|
+
if (!hasProviders && !hasProxy && !hasMode && !hasCompress && !hasPassthrough) return sendError(res, 400, "expected providers, upstream proxy, compress, or passthrough settings");
|
|
51387
51396
|
const routes = {};
|
|
51388
51397
|
if (hasProviders) {
|
|
51389
51398
|
if (!body.providers || typeof body.providers !== "object" || Array.isArray(body.providers)) {
|
|
@@ -51427,6 +51436,14 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
|
|
|
51427
51436
|
compress = body.compress === null ? {} : parseCompressSettings(body.compress);
|
|
51428
51437
|
if (compress === void 0) return sendError(res, 400, "invalid compress settings");
|
|
51429
51438
|
}
|
|
51439
|
+
if (hasPassthrough) {
|
|
51440
|
+
if (body.passthrough !== null && typeof body.passthrough !== "boolean") {
|
|
51441
|
+
return sendError(res, 400, "passthrough must be a boolean or null");
|
|
51442
|
+
}
|
|
51443
|
+
if (passthroughState(process.env).source === "env") {
|
|
51444
|
+
return sendError(res, 409, "passthrough is forced by the ACP_PASSTHROUGH environment variable (or --passthrough flag); unset it and restart to change here");
|
|
51445
|
+
}
|
|
51446
|
+
}
|
|
51430
51447
|
const config = readConfig();
|
|
51431
51448
|
if (hasProviders) config.providers = routes;
|
|
51432
51449
|
if (hasProxy) {
|
|
@@ -51438,6 +51455,10 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
|
|
|
51438
51455
|
if (compress && Object.keys(compress).length > 0) config.compress = compress;
|
|
51439
51456
|
else delete config.compress;
|
|
51440
51457
|
}
|
|
51458
|
+
if (hasPassthrough) {
|
|
51459
|
+
if (body.passthrough === true) config.passthrough = true;
|
|
51460
|
+
else delete config.passthrough;
|
|
51461
|
+
}
|
|
51441
51462
|
try {
|
|
51442
51463
|
atomicWriteConfig(config);
|
|
51443
51464
|
onChanged?.();
|
|
@@ -51448,6 +51469,7 @@ async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
|
|
|
51448
51469
|
if (hasProviders) changed.push(`${Object.keys(routes).length} routes`);
|
|
51449
51470
|
if (hasProxy || hasMode) changed.push("network");
|
|
51450
51471
|
if (hasCompress) changed.push("compress");
|
|
51472
|
+
if (hasPassthrough) changed.push("passthrough");
|
|
51451
51473
|
log("info", `[acp-web] configuration updated (${changed.join(", ") || "none"})`);
|
|
51452
51474
|
res.writeHead(200, { "content-type": "application/json" });
|
|
51453
51475
|
res.end(JSON.stringify({ ok: true, providers: hasProviders ? Object.keys(routes).length : void 0 }));
|
|
@@ -57119,8 +57141,23 @@ Content-Length: ${Buffer.byteLength(body)}\r
|
|
|
57119
57141
|
const nOverrides = Object.keys(opts.routes).length;
|
|
57120
57142
|
log2(
|
|
57121
57143
|
"info",
|
|
57122
|
-
`acp-proxy listening on http://${displayHost}:${actualPort} \u2014 web UI: http://${displayHost}:${actualPort}/__bili/ \u2014 zero-config: prefix any baseURL with http://${displayHost}:${actualPort}/bili/` + (nOverrides ? ` \u2014 context overrides for ${nOverrides} upstream URL(s)` : "") + (opts.mitm.enabled ? ` \u2014 MITM proxy on (whitelist)${opts.mitm.domains.length ? ` +${opts.mitm.domains.join(",")}` : ""}` : "")
|
|
57144
|
+
`acp-proxy listening on http://${displayHost}:${actualPort} \u2014 web UI: http://${displayHost}:${actualPort}/__bili/ \u2014 zero-config: prefix any baseURL with http://${displayHost}:${actualPort}/bili/` + (nOverrides ? ` \u2014 context overrides for ${nOverrides} upstream URL(s)` : "") + (opts.mitm.enabled ? ` \u2014 MITM proxy on (whitelist)${opts.mitm.domains.length ? ` +${opts.mitm.domains.join(",")}` : ""}` : "") + (opts.passthrough ? " \u2014 PASSTHROUGH (compression OFF)" : "")
|
|
57123
57145
|
);
|
|
57146
|
+
if (opts.passthrough) {
|
|
57147
|
+
log2(
|
|
57148
|
+
"warn",
|
|
57149
|
+
`[passthrough] compression is OFF \u2014 every request is forwarded verbatim, no tokens are saved (source: ${opts.passthroughSource === "env" ? "ACP_PASSTHROUGH env var or --passthrough flag" : `config file ${configFile()}`}). ` + (opts.passthroughSource === "env" ? "Unset ACP_PASSTHROUGH (or drop --passthrough) and restart to re-enable compression." : 'Clear it in the web UI (\u6982\u89C8 page) or remove "passthrough": true from the config file to re-enable compression.')
|
|
57150
|
+
);
|
|
57151
|
+
}
|
|
57152
|
+
const envKnobs = [];
|
|
57153
|
+
if (process.env.ACP_PASSTHROUGH !== void 0) envKnobs.push(`ACP_PASSTHROUGH=${process.env.ACP_PASSTHROUGH}`);
|
|
57154
|
+
if (process.env.ACP_MODEL_CONTEXT_LIMIT !== void 0) envKnobs.push(`ACP_MODEL_CONTEXT_LIMIT=${process.env.ACP_MODEL_CONTEXT_LIMIT}`);
|
|
57155
|
+
if (process.env.ACP_COMPRESS_TOOL !== void 0) envKnobs.push(`ACP_COMPRESS_TOOL=${process.env.ACP_COMPRESS_TOOL}`);
|
|
57156
|
+
if (process.env.ACP_COMPRESS_NUDGE !== void 0) envKnobs.push(`ACP_COMPRESS_NUDGE=${process.env.ACP_COMPRESS_NUDGE}`);
|
|
57157
|
+
if (process.env.BILI_PERSIST !== void 0) envKnobs.push(`BILI_PERSIST=${process.env.BILI_PERSIST}`);
|
|
57158
|
+
if (envKnobs.length > 0) {
|
|
57159
|
+
log2("info", `[config] env overrides active (win over the config file): ${envKnobs.join(", ")}`);
|
|
57160
|
+
}
|
|
57124
57161
|
if (nonLoopbackBind) {
|
|
57125
57162
|
log2(
|
|
57126
57163
|
"warn",
|
|
@@ -57200,9 +57237,34 @@ var SIDE_REQUEST_MAX_TOKENS = 200;
|
|
|
57200
57237
|
function isSideRequest(parsed) {
|
|
57201
57238
|
if (!parsed || typeof parsed !== "object") return false;
|
|
57202
57239
|
const p2 = parsed;
|
|
57240
|
+
if (Array.isArray(p2.tools) && p2.tools.length > 0) return false;
|
|
57203
57241
|
const raw = p2.max_tokens ?? p2.max_completion_tokens ?? p2.max_output_tokens;
|
|
57204
57242
|
return typeof raw === "number" && raw > 0 && raw <= SIDE_REQUEST_MAX_TOKENS;
|
|
57205
57243
|
}
|
|
57244
|
+
function outputBudgetField(parsed) {
|
|
57245
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
57246
|
+
const p2 = parsed;
|
|
57247
|
+
for (const field of ["max_tokens", "max_completion_tokens", "max_output_tokens"]) {
|
|
57248
|
+
if (typeof p2[field] === "number" && p2[field] > 0) return field;
|
|
57249
|
+
}
|
|
57250
|
+
return null;
|
|
57251
|
+
}
|
|
57252
|
+
function restoreOutputBudget(parsed, session, log2) {
|
|
57253
|
+
const field = outputBudgetField(parsed);
|
|
57254
|
+
if (!field) return;
|
|
57255
|
+
const p2 = parsed;
|
|
57256
|
+
const value = p2[field];
|
|
57257
|
+
if (value > SIDE_REQUEST_MAX_TOKENS) {
|
|
57258
|
+
session.metadata.outputBudgetHighWater = value;
|
|
57259
|
+
return;
|
|
57260
|
+
}
|
|
57261
|
+
if (!Array.isArray(p2.tools) || p2.tools.length === 0) return;
|
|
57262
|
+
const highWater = session.metadata.outputBudgetHighWater;
|
|
57263
|
+
if (typeof highWater === "number" && highWater > SIDE_REQUEST_MAX_TOKENS) {
|
|
57264
|
+
p2[field] = highWater;
|
|
57265
|
+
log2("info", `[${session.id}] output budget restored ${value} -> ${highWater} (#546: client shrank it from its raw-history estimate)`);
|
|
57266
|
+
}
|
|
57267
|
+
}
|
|
57206
57268
|
function isTrustedAdminOrigin(origin, host, trustedHosts) {
|
|
57207
57269
|
if (!host || !trustedHosts.has(host.toLowerCase())) return false;
|
|
57208
57270
|
if (!origin) return true;
|
|
@@ -57271,6 +57333,14 @@ async function handle(req, res, opts, core, config, log2, instanceId, instanceSt
|
|
|
57271
57333
|
if (req.method === "PUT" && req.url === "/__bili/config") {
|
|
57272
57334
|
return handleConfigPut(req, res, () => {
|
|
57273
57335
|
const fresh = loadOptions();
|
|
57336
|
+
if (fresh.passthrough !== opts.passthrough) {
|
|
57337
|
+
log2(
|
|
57338
|
+
fresh.passthrough ? "warn" : "info",
|
|
57339
|
+
`[passthrough] ${fresh.passthrough ? "compression turned OFF via web config \u2014 forwarding verbatim" : "compression re-enabled via web config"}`
|
|
57340
|
+
);
|
|
57341
|
+
}
|
|
57342
|
+
opts.passthrough = fresh.passthrough;
|
|
57343
|
+
opts.passthroughSource = fresh.passthroughSource;
|
|
57274
57344
|
opts.proxy = fresh.proxy;
|
|
57275
57345
|
opts.proxyMode = fresh.proxyMode;
|
|
57276
57346
|
opts.proxySource = fresh.proxySource;
|
|
@@ -57593,6 +57663,7 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
57593
57663
|
}
|
|
57594
57664
|
}
|
|
57595
57665
|
const pluginMode = pluginAgent !== void 0;
|
|
57666
|
+
restoreOutputBudget(parsed, session, log2);
|
|
57596
57667
|
if (!countTokens && !responsesCompact && protocol !== null && isSideRequest(parsed)) {
|
|
57597
57668
|
log2("info", `[${session.id}] side request (max_tokens<=${SIDE_REQUEST_MAX_TOKENS}) \u2192 passthrough + tag strip only, kernel state untouched`);
|
|
57598
57669
|
const sidePrepared = {
|