billion-context 0.1.46-pr.211.21 → 0.1.46-pr.211.23
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/opencode.js +54 -0
- package/dist/agent/opencode.js.map +1 -0
- package/dist/index.js +105 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createRequire as __biliCreateRequire } from 'node:module';
|
|
2
|
+
const require = __biliCreateRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/agent/opencode.ts
|
|
5
|
+
var proxyBase = process.env.BILLION_CONTEXT_PROXY ?? "";
|
|
6
|
+
async function showText(ctx, sid, text) {
|
|
7
|
+
const prompt = ctx.client?.session?.prompt;
|
|
8
|
+
if (typeof prompt !== "function") return;
|
|
9
|
+
try {
|
|
10
|
+
await prompt({
|
|
11
|
+
path: { id: sid },
|
|
12
|
+
body: { noReply: true, parts: [{ type: "text", text, ignored: true }] }
|
|
13
|
+
});
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
var server = async (ctx) => {
|
|
18
|
+
if (!proxyBase) return {};
|
|
19
|
+
console.log("[bili-opencode] plugin active (proxy " + proxyBase + ")");
|
|
20
|
+
return {
|
|
21
|
+
config: async (opencodeConfig) => {
|
|
22
|
+
opencodeConfig.command ??= {};
|
|
23
|
+
opencodeConfig.command["acp"] = {
|
|
24
|
+
template: "",
|
|
25
|
+
description: "Show ACP status (billion-context proxy)"
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
"command.execute.before": async (input) => {
|
|
29
|
+
if (input.command !== "acp") return;
|
|
30
|
+
const sid = input.sessionID;
|
|
31
|
+
let text;
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(sid)}&fallback=latest`);
|
|
34
|
+
const status = await res.json();
|
|
35
|
+
if (typeof status.panel === "string" && status.panel.length > 0) {
|
|
36
|
+
text = status.panel;
|
|
37
|
+
} else if (status.ok === false) {
|
|
38
|
+
text = "bili: no ACP session yet (send a model request first, then run /acp)";
|
|
39
|
+
} else {
|
|
40
|
+
text = "bili: proxy returned no status panel";
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
text = `bili: /acp failed (${err instanceof Error ? err.message : String(err)})`;
|
|
44
|
+
}
|
|
45
|
+
await showText(ctx, sid, text);
|
|
46
|
+
throw new Error("__BILI_ACP_HANDLED__");
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
var opencode_default = server;
|
|
51
|
+
export {
|
|
52
|
+
opencode_default as default
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/agent/opencode.ts"],"sourcesContent":["// Thin opencode plugin for the billion-context proxy (`bili opencode`).\n//\n// Activates ONLY when BILLION_CONTEXT_PROXY is set (the launcher sets it);\n// otherwise it is a no-op so shipping it inside the package is harmless.\n// Mirrors the pi/omp plugin (src/agent/pi.ts):\n// - registers the /acp command (config hook + command.execute.before)\n// - binds the opencode session id to the proxy session via the\n// pending-register queue (POST /__bili/plugin/register on session.created)\n// - renders the proxy's buildStatusPanel via an ignored chat message\n\ninterface OpencodeCommandConfig {\n template: string;\n description?: string;\n}\n\ninterface OpencodeConfig {\n command?: Record<string, OpencodeCommandConfig>;\n [key: string]: unknown;\n}\n\ninterface OpencodeSessionInfo {\n id?: unknown;\n}\n\ninterface OpencodeEvent {\n type?: string;\n properties?: { info?: OpencodeSessionInfo; [key: string]: unknown };\n}\n\ninterface OpencodeEventInput {\n event?: OpencodeEvent;\n}\n\ninterface OpencodeCommandInput {\n command: string;\n sessionID: string;\n arguments?: string;\n}\n\ninterface OpencodePromptPart {\n type: string;\n text: string;\n ignored?: boolean;\n}\n\ninterface OpencodeClient {\n session?: {\n prompt?: (args: {\n path: { id: string };\n body: { noReply: boolean; parts: OpencodePromptPart[] };\n }) => Promise<unknown>;\n };\n}\n\ninterface OpencodePluginContext {\n client?: OpencodeClient;\n}\n\ninterface OpencodeHooks {\n config?: (input: OpencodeConfig) => Promise<void>;\n event?: (input: OpencodeEventInput) => Promise<void>;\n \"command.execute.before\"?: (input: OpencodeCommandInput, output: { parts: unknown[] }) => Promise<void>;\n}\n\nconst proxyBase = process.env.BILLION_CONTEXT_PROXY ?? \"\";\n\nasync function showText(ctx: OpencodePluginContext, sid: string, text: string): Promise<void> {\n const prompt = ctx.client?.session?.prompt;\n if (typeof prompt !== \"function\") return;\n try {\n await prompt({\n path: { id: sid },\n body: { noReply: true, parts: [{ type: \"text\", text, ignored: true }] },\n });\n } catch {}\n}\n\nconst server = async (ctx: OpencodePluginContext): Promise<OpencodeHooks> => {\n if (!proxyBase) return {};\n console.log(\"[bili-opencode] plugin active (proxy \" + proxyBase + \")\");\n return {\n config: async (opencodeConfig) => {\n opencodeConfig.command ??= {};\n opencodeConfig.command[\"acp\"] = {\n template: \"\",\n description: \"Show ACP status (billion-context proxy)\",\n };\n },\n \"command.execute.before\": async (input) => {\n if (input.command !== \"acp\") return;\n const sid = input.sessionID;\n let text: string;\n try {\n const res = await fetch(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(sid)}&fallback=latest`);\n const status = (await res.json()) as { ok?: boolean; panel?: string; error?: string };\n if (typeof status.panel === \"string\" && status.panel.length > 0) {\n text = status.panel;\n } else if (status.ok === false) {\n text = \"bili: no ACP session yet (send a model request first, then run /acp)\";\n } else {\n text = \"bili: proxy returned no status panel\";\n }\n } catch (err) {\n text = `bili: /acp failed (${err instanceof Error ? err.message : String(err)})`;\n }\n await showText(ctx, sid, text);\n throw new Error(\"__BILI_ACP_HANDLED__\");\n },\n };\n};\n\nexport default server;\n"],"mappings":";;;;AAgEA,IAAM,YAAY,QAAQ,IAAI,yBAAyB;AAEvD,eAAe,SAAS,KAA4B,KAAa,MAA6B;AACtF,QAAM,SAAS,IAAI,QAAQ,SAAS;AACpC,MAAI,OAAO,WAAW,WAAY;AAClC,MAAI;AACA,UAAM,OAAO;AAAA,MACT,MAAM,EAAE,IAAI,IAAI;AAAA,MAChB,MAAM,EAAE,SAAS,MAAM,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,IAC1E,CAAC;AAAA,EACL,QAAQ;AAAA,EAAC;AACjB;AAEA,IAAM,SAAS,OAAO,QAAuD;AACzE,MAAI,CAAC,UAAW,QAAO,CAAC;AACxB,UAAQ,IAAI,0CAA0C,YAAY,GAAG;AACrE,SAAO;AAAA,IACH,QAAQ,OAAO,mBAAmB;AAC9B,qBAAe,YAAY,CAAC;AAC5B,qBAAe,QAAQ,KAAK,IAAI;AAAA,QAC5B,UAAU;AAAA,QACV,aAAa;AAAA,MACjB;AAAA,IACJ;AAAA,IACA,0BAA0B,OAAO,UAAU;AACvC,UAAI,MAAM,YAAY,MAAO;AAC7B,YAAM,MAAM,MAAM;AAClB,UAAI;AACJ,UAAI;AACA,cAAM,MAAM,MAAM,MAAM,GAAG,SAAS,wCAAwC,mBAAmB,GAAG,CAAC,kBAAkB;AACrH,cAAM,SAAU,MAAM,IAAI,KAAK;AAC/B,YAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,SAAS,GAAG;AAC7D,iBAAO,OAAO;AAAA,QAClB,WAAW,OAAO,OAAO,OAAO;AAC5B,iBAAO;AAAA,QACX,OAAO;AACH,iBAAO;AAAA,QACX;AAAA,MACJ,SAAS,KAAK;AACV,eAAO,sBAAsB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACjF;AACA,YAAM,SAAS,KAAK,KAAK,IAAI;AAC7B,YAAM,IAAI,MAAM,sBAAsB;AAAA,IAC1C;AAAA,EACJ;AACJ;AAEA,IAAO,mBAAQ;","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -51706,15 +51706,23 @@ function handlePluginManifest(res) {
|
|
|
51706
51706
|
statusEndpoint: "/__bili/plugin/status"
|
|
51707
51707
|
}));
|
|
51708
51708
|
}
|
|
51709
|
-
function handlePluginStatus(conversationId2, res) {
|
|
51710
|
-
|
|
51711
|
-
|
|
51712
|
-
|
|
51709
|
+
function handlePluginStatus(conversationId2, res, fallbackLatest = false) {
|
|
51710
|
+
let entry = conversations.get(conversationId2);
|
|
51711
|
+
let session = entry ? peekSession(entry.sessionId) : void 0;
|
|
51712
|
+
let viaFallback = false;
|
|
51713
|
+
if ((!entry || !session) && fallbackLatest) {
|
|
51714
|
+
const latest = listSessions().filter((s3) => typeof s3.lastSeen === "number").sort((a, b2) => (b2.lastSeen ?? 0) - (a.lastSeen ?? 0))[0];
|
|
51715
|
+
if (latest) {
|
|
51716
|
+
session = latest;
|
|
51717
|
+
viaFallback = true;
|
|
51718
|
+
}
|
|
51719
|
+
}
|
|
51720
|
+
if (!session) {
|
|
51713
51721
|
res.writeHead(404, { "content-type": "application/json" });
|
|
51714
51722
|
res.end(JSON.stringify({ ok: false, error: "unknown plugin conversation" }));
|
|
51715
51723
|
return;
|
|
51716
51724
|
}
|
|
51717
|
-
entry.lastSeen = Date.now();
|
|
51725
|
+
if (entry) entry.lastSeen = Date.now();
|
|
51718
51726
|
const limit = session.metadata.effectiveContextLimit;
|
|
51719
51727
|
const mem = remembered.get(session.id);
|
|
51720
51728
|
const modelContextLimit = typeof limit === "number" && limit > 0 ? limit : 2e5;
|
|
@@ -51736,7 +51744,7 @@ function handlePluginStatus(conversationId2, res) {
|
|
|
51736
51744
|
res.end(JSON.stringify({
|
|
51737
51745
|
ok: true,
|
|
51738
51746
|
conversationId: conversationId2,
|
|
51739
|
-
|
|
51747
|
+
fallback: viaFallback || void 0,
|
|
51740
51748
|
label: session.meta.label ?? null,
|
|
51741
51749
|
pluginAgent: session.metadata.pluginAgent ?? null,
|
|
51742
51750
|
contextLimit: typeof limit === "number" ? limit : null,
|
|
@@ -52217,6 +52225,41 @@ function readOmpConfig(ompHome) {
|
|
|
52217
52225
|
}
|
|
52218
52226
|
return parseOmpYaml(text);
|
|
52219
52227
|
}
|
|
52228
|
+
function resolveOpencodeConfigFile(env) {
|
|
52229
|
+
if (nonEmpty2(env.OPENCODE_CONFIG)) return env.OPENCODE_CONFIG;
|
|
52230
|
+
const xdg2 = nonEmpty2(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path8.join(os.homedir(), ".config");
|
|
52231
|
+
return path8.join(xdg2, "opencode", "opencode.json");
|
|
52232
|
+
}
|
|
52233
|
+
function readOpencodeConfig(file) {
|
|
52234
|
+
let text;
|
|
52235
|
+
try {
|
|
52236
|
+
text = fs4.readFileSync(file, "utf8");
|
|
52237
|
+
} catch {
|
|
52238
|
+
return { providers: {} };
|
|
52239
|
+
}
|
|
52240
|
+
let parsed;
|
|
52241
|
+
try {
|
|
52242
|
+
parsed = JSON.parse(text);
|
|
52243
|
+
} catch {
|
|
52244
|
+
return { providers: {} };
|
|
52245
|
+
}
|
|
52246
|
+
const providers = {};
|
|
52247
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
52248
|
+
const root = parsed;
|
|
52249
|
+
const provRoot = root.provider;
|
|
52250
|
+
if (provRoot && typeof provRoot === "object" && !Array.isArray(provRoot)) {
|
|
52251
|
+
for (const [name, value] of Object.entries(provRoot)) {
|
|
52252
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
52253
|
+
const opts = value.options;
|
|
52254
|
+
if (opts && typeof opts === "object" && !Array.isArray(opts)) {
|
|
52255
|
+
const baseURL = opts.baseURL;
|
|
52256
|
+
if (typeof baseURL === "string") providers[name] = { baseURL };
|
|
52257
|
+
}
|
|
52258
|
+
}
|
|
52259
|
+
}
|
|
52260
|
+
}
|
|
52261
|
+
return { providers };
|
|
52262
|
+
}
|
|
52220
52263
|
function parseZcodeConfig(obj) {
|
|
52221
52264
|
const result = { providers: {} };
|
|
52222
52265
|
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return result;
|
|
@@ -52259,6 +52302,7 @@ function loadClientConfig(env, cwd) {
|
|
|
52259
52302
|
const zcodeHome = nonEmpty2(env.ZCODE_DATA_BASE_DIR) ? env.ZCODE_DATA_BASE_DIR : path8.join(home, ".zcode");
|
|
52260
52303
|
config.zcode = readZcodeConfig(zcodeHome);
|
|
52261
52304
|
config.omp = readOmpConfig(resolveOmpHome(env));
|
|
52305
|
+
config.opencode = readOpencodeConfig(resolveOpencodeConfigFile(env));
|
|
52262
52306
|
return config;
|
|
52263
52307
|
}
|
|
52264
52308
|
|
|
@@ -53483,13 +53527,14 @@ async function handle(req, res, opts, core, config, log2) {
|
|
|
53483
53527
|
if (req.method === "GET" && req.url === "/__bili/plugin/manifest") return handlePluginManifest(res);
|
|
53484
53528
|
if (req.method === "GET" && req.url?.startsWith("/__bili/plugin/status")) {
|
|
53485
53529
|
const query = req.url.slice(req.url.indexOf("?") + 1);
|
|
53486
|
-
const
|
|
53530
|
+
const params = new URLSearchParams(query);
|
|
53531
|
+
const conversationId2 = params.get("conversationId")?.trim() ?? "";
|
|
53487
53532
|
if (!conversationId2) {
|
|
53488
53533
|
res.writeHead(400, { "content-type": "application/json" });
|
|
53489
53534
|
res.end(JSON.stringify({ ok: false, error: "conversationId query parameter is required" }));
|
|
53490
53535
|
return;
|
|
53491
53536
|
}
|
|
53492
|
-
return handlePluginStatus(conversationId2, res);
|
|
53537
|
+
return handlePluginStatus(conversationId2, res, params.get("fallback") === "latest");
|
|
53493
53538
|
}
|
|
53494
53539
|
if (req.method === "POST" && req.url === "/__bili/plugin/tool") {
|
|
53495
53540
|
try {
|
|
@@ -58438,6 +58483,10 @@ function discoverRoutes(client, config) {
|
|
|
58438
58483
|
for (const [name, prov] of Object.entries(config.omp?.providers ?? {})) {
|
|
58439
58484
|
classify(prov.baseUrl, name);
|
|
58440
58485
|
}
|
|
58486
|
+
} else if (client === "opencode") {
|
|
58487
|
+
for (const [name, prov] of Object.entries(config.opencode?.providers ?? {})) {
|
|
58488
|
+
classify(prov.baseURL, name);
|
|
58489
|
+
}
|
|
58441
58490
|
} else {
|
|
58442
58491
|
for (const [name, prov] of Object.entries(config.codex?.providers ?? {})) {
|
|
58443
58492
|
classify(prov.baseUrl, `model_providers.${name}.base_url`);
|
|
@@ -58616,6 +58665,43 @@ function prepareOmpHttpRewrite(ompHome, origin, httpRewrites, httpsRewrites) {
|
|
|
58616
58665
|
fs10.writeFileSync(path13.join(tmp, "models.yml"), lines.join("\n"));
|
|
58617
58666
|
return tmp;
|
|
58618
58667
|
}
|
|
58668
|
+
function prepareOpencodeHttpRewrite(configFile2, origin, httpRewrites, httpsRewrites, pluginPath) {
|
|
58669
|
+
if (httpRewrites.length === 0 && httpsRewrites.length === 0 && !pluginPath) return void 0;
|
|
58670
|
+
let root = {};
|
|
58671
|
+
try {
|
|
58672
|
+
const txt = fs10.readFileSync(configFile2, "utf8");
|
|
58673
|
+
const parsed = JSON.parse(txt);
|
|
58674
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
58675
|
+
root = { ...parsed };
|
|
58676
|
+
}
|
|
58677
|
+
} catch {
|
|
58678
|
+
}
|
|
58679
|
+
const provRoot = root.provider;
|
|
58680
|
+
if (provRoot && typeof provRoot === "object" && !Array.isArray(provRoot)) {
|
|
58681
|
+
const providers = provRoot;
|
|
58682
|
+
const rewrite = (rewrites, wrap) => {
|
|
58683
|
+
for (const r of rewrites) {
|
|
58684
|
+
const prov = providers[r.key];
|
|
58685
|
+
if (!prov || typeof prov !== "object" || Array.isArray(prov)) continue;
|
|
58686
|
+
const p2 = prov;
|
|
58687
|
+
if (!p2.options || typeof p2.options !== "object") continue;
|
|
58688
|
+
const existing = typeof p2.options.baseURL === "string" ? p2.options.baseURL : r.realUpstream;
|
|
58689
|
+
p2.options.baseURL = wrap ? wrapUpstream(origin, unwrapUpstream2(existing)) : r.realUpstream;
|
|
58690
|
+
}
|
|
58691
|
+
};
|
|
58692
|
+
rewrite(httpRewrites, true);
|
|
58693
|
+
rewrite(httpsRewrites, false);
|
|
58694
|
+
}
|
|
58695
|
+
if (pluginPath) {
|
|
58696
|
+
const plugins = Array.isArray(root.plugin) ? root.plugin.filter((p2) => typeof p2 === "string") : [];
|
|
58697
|
+
if (!plugins.includes(pluginPath)) plugins.push(pluginPath);
|
|
58698
|
+
root.plugin = plugins;
|
|
58699
|
+
}
|
|
58700
|
+
const tmp = fs10.mkdtempSync(path13.join(os5.tmpdir(), "bili-opencode-"));
|
|
58701
|
+
const tmpFile = path13.join(tmp, "opencode.json");
|
|
58702
|
+
fs10.writeFileSync(tmpFile, JSON.stringify(root));
|
|
58703
|
+
return tmpFile;
|
|
58704
|
+
}
|
|
58619
58705
|
function dedupeInOrder(list) {
|
|
58620
58706
|
const seen = /* @__PURE__ */ new Set();
|
|
58621
58707
|
const out = [];
|
|
@@ -58820,6 +58906,7 @@ async function runLaunch(params, deps = {}) {
|
|
|
58820
58906
|
let clientArgs = params.clientArgs;
|
|
58821
58907
|
let piTmpHome;
|
|
58822
58908
|
let ompTmpHome;
|
|
58909
|
+
let opencodeTmpFile;
|
|
58823
58910
|
const tmpFiles = [];
|
|
58824
58911
|
const directUrl = launcherDirectUrl(process.env);
|
|
58825
58912
|
if (directUrl) {
|
|
@@ -58848,6 +58935,10 @@ async function runLaunch(params, deps = {}) {
|
|
|
58848
58935
|
if (ompTmpHome) env.PI_CODING_AGENT_DIR = ompTmpHome;
|
|
58849
58936
|
} else if (base === "opencode") {
|
|
58850
58937
|
env = { ...process.env, HTTPS_PROXY: origin, NODE_EXTRA_CA_CERTS: ca, BILLION_CONTEXT_PROXY: origin };
|
|
58938
|
+
const opencodePlugin = process.argv[1] ? path13.resolve(path13.dirname(process.argv[1]), "agent", "opencode.js") : void 0;
|
|
58939
|
+
const opencodePluginPath = opencodePlugin && fs10.existsSync(opencodePlugin) ? opencodePlugin : void 0;
|
|
58940
|
+
opencodeTmpFile = prepareOpencodeHttpRewrite(resolveOpencodeConfigFile(process.env), origin, routes.httpRewrites, routes.httpsRewrites, opencodePluginPath);
|
|
58941
|
+
if (opencodeTmpFile) env.OPENCODE_CONFIG = opencodeTmpFile;
|
|
58851
58942
|
} else if (base === "codex") {
|
|
58852
58943
|
const codexConversationId = injectMcp ? randomUUID2() : void 0;
|
|
58853
58944
|
if (directUrl) {
|
|
@@ -58892,6 +58983,12 @@ async function runLaunch(params, deps = {}) {
|
|
|
58892
58983
|
} catch {
|
|
58893
58984
|
}
|
|
58894
58985
|
}
|
|
58986
|
+
if (opencodeTmpFile) {
|
|
58987
|
+
try {
|
|
58988
|
+
fs10.rmSync(path13.dirname(opencodeTmpFile), { recursive: true, force: true });
|
|
58989
|
+
} catch {
|
|
58990
|
+
}
|
|
58991
|
+
}
|
|
58895
58992
|
for (const f2 of tmpFiles) {
|
|
58896
58993
|
try {
|
|
58897
58994
|
fs10.rmSync(f2, { force: true });
|