billion-context 0.1.47 → 0.1.48-pr.219.34
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 +9 -6
- package/dist/agent/omp.js.map +1 -1
- package/dist/agent/pi.js +9 -6
- package/dist/agent/pi.js.map +1 -1
- package/dist/index.js +81 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/agent/omp.js
CHANGED
|
@@ -165,6 +165,7 @@ async function registerTools(pi, ctx, state, agent) {
|
|
|
165
165
|
try {
|
|
166
166
|
for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));
|
|
167
167
|
state.sid = sid;
|
|
168
|
+
state.toolsReady = true;
|
|
168
169
|
state.retryAt = void 0;
|
|
169
170
|
} catch (err) {
|
|
170
171
|
state.sid = void 0;
|
|
@@ -219,12 +220,14 @@ function createBiliPlugin(agentOverride) {
|
|
|
219
220
|
if (proxyBaseForCtx(ctx) === void 0) return;
|
|
220
221
|
const headers = event.headers;
|
|
221
222
|
if (headers === void 0 || typeof headers !== "object" || Array.isArray(headers)) return;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
if (state.toolsReady === true) {
|
|
224
|
+
const sid = sessionIdOf(ctx);
|
|
225
|
+
if (sid !== void 0) headers["x-bili-plugin-conversation"] = sid;
|
|
226
|
+
headers["x-bili-plugin"] = agent;
|
|
227
|
+
const window = ctx.model?.contextWindow;
|
|
228
|
+
if (typeof window === "number" && Number.isFinite(window) && window > 0) {
|
|
229
|
+
headers["x-bili-plugin-context-window"] = String(Math.floor(window));
|
|
230
|
+
}
|
|
228
231
|
}
|
|
229
232
|
} catch (err) {
|
|
230
233
|
console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);
|
package/dist/agent/omp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/shared.ts","../../src/agent/pi.ts","../../src/agent/omp.ts"],"sourcesContent":["// Shared thin-plugin core for agent-side extensions (\"内外呼应\", issue #1).\n// The agent plugin is a PURE PROTOCOL CLIENT: no acp-kernel import, no\n// compression logic. The proxy stays the single compression authority; the\n// plugin only (1) detects the proxy, (2) fetches the tool manifest (single\n// source of truth), (3) forwards tool executes, (4) reads status. Same\n// package as the proxy ⇒ same version ⇒ no kernel-skew bug class.\n\nexport type ManifestTool = {\n name: string;\n description?: string;\n inputSchema: unknown;\n};\n\nconst MANIFEST_TIMEOUT_MS = 5000;\nconst TOOL_TIMEOUT_MS = 60000;\nconst STATUS_TIMEOUT_MS = 5000;\n\n/** Detect the proxy from a provider baseUrl's `/bili/` zero-config prefix.\n * The real prefix embeds the full upstream URL (`/bili/https://…`), so the\n * check requires `bili` as the first path segment followed by an http(s)\n * URL — a plain `/foo/bili/` path segment is NOT a bili proxy.\n * Returns the proxy origin (scheme//host) the request will actually hit. */\nexport function proxyBaseFromUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined;\n try {\n const url = new URL(baseUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n const segments = url.pathname.split(\"/\").filter((s) => s.length > 0);\n if (segments[0] !== \"bili\") return undefined;\n const rest = url.pathname.slice(url.pathname.indexOf(\"bili\") + \"bili\".length);\n if (!/^\\/https?:\\/\\//.test(rest)) return undefined;\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\n/** MITM transparent mode has no `/bili/` prefix; the proxy's launcher exports\n * BILLION_CONTEXT_PROXY. A stale value surfaces as a tool-forward error. */\nexport function proxyBaseFromEnv(): string | undefined {\n const raw = process.env.BILLION_CONTEXT_PROXY?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? `${url.protocol}//${url.host}` : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function detectProxyBase(baseUrl: string | undefined): string | undefined {\n if (process.env.BILLION_CONTEXT_PLUGIN === \"0\") return undefined;\n return proxyBaseFromUrl(baseUrl) ?? proxyBaseFromEnv();\n}\n\nasync function fetchJson(url: string, init: RequestInit | undefined, timeoutMs: number, externalSignal?: AbortSignal): Promise<{ ok: boolean; status: number; json: unknown }> {\n const ac = new AbortController();\n // An already-aborted external signal never fires its \"abort\" event, so\n // forward the state directly — otherwise only the timeout could stop\n // the request, turning an instant cancel into a timeout wait.\n if (externalSignal?.aborted) ac.abort();\n const timer = setTimeout(() => ac.abort(), timeoutMs);\n const onExternalAbort = () => ac.abort();\n externalSignal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n try {\n let res: Response;\n try {\n res = await fetch(url, { ...init, signal: ac.signal });\n } catch (err) {\n if (ac.signal.aborted && !externalSignal?.aborted) throw new Error(`timeout after ${timeoutMs}ms: ${url}`);\n throw err;\n }\n const text = await res.text();\n let json: unknown = undefined;\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json };\n } finally {\n clearTimeout(timer);\n externalSignal?.removeEventListener(\"abort\", onExternalAbort);\n }\n}\n\nexport async function fetchManifest(proxyBase: string): Promise<ManifestTool[]> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/manifest`, undefined, MANIFEST_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") throw new Error(`manifest fetch failed: ${status}`);\n const data = json as { tools?: { anthropic?: { name?: string; description?: string; input_schema?: unknown }[] } };\n const tools = (data.tools?.anthropic ?? []).filter((t): t is { name: string; description?: string; input_schema?: unknown } => typeof t.name === \"string\");\n if (tools.length === 0) throw new Error(\"manifest served no anthropic tools\");\n return tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.input_schema ?? { type: \"object\", properties: {} } }));\n}\n\nexport async function forwardTool(proxyBase: string, conversationId: string, tool: string, args: unknown, signal?: AbortSignal): Promise<string> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/tool`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ conversationId, tool, args: args ?? {} }),\n }, TOOL_TIMEOUT_MS, signal);\n const data = json as { ok?: boolean; result?: string; error?: string } | undefined;\n if (!ok || !data?.ok) {\n throw new Error(`bili proxy tool ${tool} failed (${status}): ${data?.error ?? \"unknown error\"}`);\n }\n return data.result ?? \"\";\n}\n\n/** Soft-fail by design: the status read is best-effort UI data; undefined\n * means \"no data\" whether the proxy is down or the session is unknown. */\nexport async function fetchStatus(proxyBase: string, conversationId: string): Promise<Record<string, unknown> | undefined> {\n const { ok, json } = await fetchJson(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId)}`, undefined, STATUS_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") return undefined;\n return json as Record<string, unknown>;\n}\n","// Thin agent extension for pi and omp (\"内外呼应\", issue #1). Loaded by pi\n// via the package.json `pi` manifest (dist/agent/pi.js) or by omp via the\n// config.yml `extensions:` list (dist/agent/omp.js). pi and omp share the\n// ExtensionFactory API shape, so one factory serves both; types below are\n// minimal structural declarations — the bundled artifact imports NOTHING\n// from the host at runtime (the host duck-types us in).\n\nimport { detectProxyBase, fetchManifest, forwardTool, fetchStatus, type ManifestTool } from \"./shared.js\";\n\ntype Ctx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n cwd?: string;\n};\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolResult = { content: TextBlock[]; isError?: boolean };\n\ntype ToolDefinition = {\n name: string;\n description?: string;\n parameters: unknown;\n execute: (toolCallId: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: ((u: unknown) => void) | undefined, ctx: Ctx) => Promise<ToolResult>;\n};\n\ntype CommandCtx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n ui?: { notify?: (message: string, type?: string) => void } | undefined;\n};\n\ntype ExtensionAPI = {\n on: (event: string, handler: (event: never, ctx: Ctx) => unknown) => void;\n registerTool: (tool: ToolDefinition) => void;\n registerCommand?: (name: string, options: { description?: string; handler: (args: string, ctx: CommandCtx) => void | Promise<void> }) => void;\n};\n\nfunction agentName(override: string | undefined): string {\n if (override) return override;\n return process.env.BILLION_CONTEXT_PLUGIN_AGENT === \"omp\" ? \"omp\" : \"pi\";\n}\n\nfunction proxyBaseForCtx(ctx: Ctx): string | undefined {\n return detectProxyBase(ctx.model?.baseUrl);\n}\n\nfunction sessionIdOf(ctx: Ctx): string | undefined {\n try {\n const sid = ctx.sessionManager?.getSessionId?.();\n return typeof sid === \"string\" ? sid : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction fmtTok(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}K`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction renderAcpStatus(s: Record<string, unknown>): string {\n const num = (v: unknown): number | null => (typeof v === \"number\" && Number.isFinite(v) ? v : null);\n const contextTokens = num(s.contextTokens);\n const contextLimit = num(s.contextLimit);\n const inputTokens = num(s.inputTokens);\n const outputTokens = num(s.outputTokens);\n const cachedTokens = num(s.cachedTokens);\n const requests = num(s.requests);\n const blocks = Array.isArray(s.blocks) ? (s.blocks as Array<{ tier?: number; active?: boolean }>) : [];\n const activeBlocks = blocks.filter((b) => b.active === true).length;\n const lines: string[] = [\"📊 ACP status\"];\n if (contextTokens !== null) {\n const pct = contextLimit !== null && contextLimit > 0 ? ` (${((contextTokens / contextLimit) * 100).toFixed(1)}%)` : \"\";\n lines.push(` context: ${fmtTok(contextTokens)}${contextLimit !== null ? ` / ${fmtTok(contextLimit)}` : \"\"}${pct}`);\n }\n if (inputTokens !== null || outputTokens !== null || cachedTokens !== null) {\n lines.push(` in/out/cached: ${fmtTok(inputTokens ?? 0)} / ${fmtTok(outputTokens ?? 0)} / ${fmtTok(cachedTokens ?? 0)}`);\n }\n if (requests !== null) lines.push(` requests: ${requests}`);\n if (blocks.length > 0) lines.push(` blocks: ${blocks.length} (${activeBlocks} active)`);\n return lines.join(\"\\n\");\n}\n\nfunction manifestToTool(proxyBase: string, tool: ManifestTool, agent: string): ToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n try {\n const output = await forwardTool(proxyBase, conversationId, tool.name, params, signal);\n return { content: [{ type: \"text\", text: output }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `bili tool error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n };\n}\n\nconst RETRY_INTERVAL_MS = 10000;\n\ntype RegisterState = { sid?: string; pending?: Promise<void>; retryAt?: number };\n\nasync function registerTools(pi: ExtensionAPI, ctx: Ctx, state: RegisterState, agent: string): Promise<void> {\n const proxyBase = proxyBaseForCtx(ctx);\n if (proxyBase === undefined) return;\n // Cache on the session id; \"\" (host has no sessionManager) still caches,\n // so a successful registration is not re-fetched on every provider\n // request — the manifest is session-independent anyway.\n const sid = sessionIdOf(ctx) ?? \"\";\n if (sid === state.sid) return;\n if (state.pending !== undefined) return state.pending;\n if (state.retryAt !== undefined && Date.now() < state.retryAt) return;\n state.pending = (async () => {\n let tools: ManifestTool[];\n try {\n tools = await fetchManifest(proxyBase);\n } catch (err) {\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): manifest fetch failed: ${err instanceof Error ? err.message : String(err)} — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n return;\n }\n try {\n for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));\n state.sid = sid;\n state.retryAt = undefined;\n } catch (err) {\n state.sid = undefined;\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): tool registration deferred (${err instanceof Error ? err.message : String(err)}) — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n }\n })();\n try {\n await state.pending;\n } finally {\n state.pending = undefined;\n }\n}\n\nexport function createBiliPlugin(agentOverride?: string): (pi: ExtensionAPI) => void {\n return function biliPlugin(pi: ExtensionAPI): void {\n const agent = agentName(agentOverride);\n const state: RegisterState = {};\n if (typeof pi.registerCommand === \"function\") {\n pi.registerCommand(\"acp\", {\n description: \"Show ACP context-compression status for this session\",\n handler: async (_args, ctx) => {\n const notify = (message: string, type?: string): void => {\n try {\n ctx.ui?.notify?.(message, type);\n } catch {\n // host UI unavailable — the command is best-effort\n }\n };\n const proxyBase = detectProxyBase(ctx.model?.baseUrl);\n if (proxyBase === undefined) {\n notify(\"bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)\", \"warning\");\n return;\n }\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n let status: Record<string, unknown> | undefined;\n try {\n status = await fetchStatus(proxyBase, conversationId);\n } catch (err) {\n notify(`bili: status fetch failed: ${err instanceof Error ? err.message : String(err)}`, \"error\");\n return;\n }\n if (status === undefined) {\n notify(\"bili: no ACP session yet (send a model request first, then run /acp)\", \"warning\");\n return;\n }\n const panel = typeof status.panel === \"string\" ? status.panel : undefined;\n notify(panel ?? renderAcpStatus(status), \"info\");\n },\n });\n }\n pi.on(\"before_provider_headers\", (event, ctx) => {\n try {\n if (proxyBaseForCtx(ctx) === undefined) return;\n const headers = (event as unknown as { headers?: Record<string, string> }).headers;\n if (headers === undefined || typeof headers !== \"object\" || Array.isArray(headers)) return;\n const sid = sessionIdOf(ctx);\n if (sid !== undefined) headers[\"x-bili-plugin-conversation\"] = sid;\n headers[\"x-bili-plugin\"] = agent;\n const window = ctx.model?.contextWindow;\n if (typeof window === \"number\" && Number.isFinite(window) && window > 0) {\n headers[\"x-bili-plugin-context-window\"] = String(Math.floor(window));\n }\n } catch (err) {\n console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);\n }\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n pi.on(\"session_start\", (_event, ctx) => {\n state.sid = undefined;\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n };\n}\n\nexport default createBiliPlugin();\n\nexport { fetchStatus };\n","import { createBiliPlugin } from \"./pi.js\";\n\nexport default createBiliPlugin(\"omp\");\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/shared.ts","../../src/agent/pi.ts","../../src/agent/omp.ts"],"sourcesContent":["// Shared thin-plugin core for agent-side extensions (\"内外呼应\", issue #1).\n// The agent plugin is a PURE PROTOCOL CLIENT: no acp-kernel import, no\n// compression logic. The proxy stays the single compression authority; the\n// plugin only (1) detects the proxy, (2) fetches the tool manifest (single\n// source of truth), (3) forwards tool executes, (4) reads status. Same\n// package as the proxy ⇒ same version ⇒ no kernel-skew bug class.\n\nexport type ManifestTool = {\n name: string;\n description?: string;\n inputSchema: unknown;\n};\n\nconst MANIFEST_TIMEOUT_MS = 5000;\nconst TOOL_TIMEOUT_MS = 60000;\nconst STATUS_TIMEOUT_MS = 5000;\n\n/** Detect the proxy from a provider baseUrl's `/bili/` zero-config prefix.\n * The real prefix embeds the full upstream URL (`/bili/https://…`), so the\n * check requires `bili` as the first path segment followed by an http(s)\n * URL — a plain `/foo/bili/` path segment is NOT a bili proxy.\n * Returns the proxy origin (scheme//host) the request will actually hit. */\nexport function proxyBaseFromUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined;\n try {\n const url = new URL(baseUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n const segments = url.pathname.split(\"/\").filter((s) => s.length > 0);\n if (segments[0] !== \"bili\") return undefined;\n const rest = url.pathname.slice(url.pathname.indexOf(\"bili\") + \"bili\".length);\n if (!/^\\/https?:\\/\\//.test(rest)) return undefined;\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\n/** MITM transparent mode has no `/bili/` prefix; the proxy's launcher exports\n * BILLION_CONTEXT_PROXY. A stale value surfaces as a tool-forward error. */\nexport function proxyBaseFromEnv(): string | undefined {\n const raw = process.env.BILLION_CONTEXT_PROXY?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? `${url.protocol}//${url.host}` : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function detectProxyBase(baseUrl: string | undefined): string | undefined {\n if (process.env.BILLION_CONTEXT_PLUGIN === \"0\") return undefined;\n return proxyBaseFromUrl(baseUrl) ?? proxyBaseFromEnv();\n}\n\nasync function fetchJson(url: string, init: RequestInit | undefined, timeoutMs: number, externalSignal?: AbortSignal): Promise<{ ok: boolean; status: number; json: unknown }> {\n const ac = new AbortController();\n // An already-aborted external signal never fires its \"abort\" event, so\n // forward the state directly — otherwise only the timeout could stop\n // the request, turning an instant cancel into a timeout wait.\n if (externalSignal?.aborted) ac.abort();\n const timer = setTimeout(() => ac.abort(), timeoutMs);\n const onExternalAbort = () => ac.abort();\n externalSignal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n try {\n let res: Response;\n try {\n res = await fetch(url, { ...init, signal: ac.signal });\n } catch (err) {\n if (ac.signal.aborted && !externalSignal?.aborted) throw new Error(`timeout after ${timeoutMs}ms: ${url}`);\n throw err;\n }\n const text = await res.text();\n let json: unknown = undefined;\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json };\n } finally {\n clearTimeout(timer);\n externalSignal?.removeEventListener(\"abort\", onExternalAbort);\n }\n}\n\nexport async function fetchManifest(proxyBase: string): Promise<ManifestTool[]> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/manifest`, undefined, MANIFEST_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") throw new Error(`manifest fetch failed: ${status}`);\n const data = json as { tools?: { anthropic?: { name?: string; description?: string; input_schema?: unknown }[] } };\n const tools = (data.tools?.anthropic ?? []).filter((t): t is { name: string; description?: string; input_schema?: unknown } => typeof t.name === \"string\");\n if (tools.length === 0) throw new Error(\"manifest served no anthropic tools\");\n return tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.input_schema ?? { type: \"object\", properties: {} } }));\n}\n\nexport async function forwardTool(proxyBase: string, conversationId: string, tool: string, args: unknown, signal?: AbortSignal): Promise<string> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/tool`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ conversationId, tool, args: args ?? {} }),\n }, TOOL_TIMEOUT_MS, signal);\n const data = json as { ok?: boolean; result?: string; error?: string } | undefined;\n if (!ok || !data?.ok) {\n throw new Error(`bili proxy tool ${tool} failed (${status}): ${data?.error ?? \"unknown error\"}`);\n }\n return data.result ?? \"\";\n}\n\n/** Soft-fail by design: the status read is best-effort UI data; undefined\n * means \"no data\" whether the proxy is down or the session is unknown. */\nexport async function fetchStatus(proxyBase: string, conversationId: string): Promise<Record<string, unknown> | undefined> {\n const { ok, json } = await fetchJson(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId)}`, undefined, STATUS_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") return undefined;\n return json as Record<string, unknown>;\n}\n","// Thin agent extension for pi and omp (\"内外呼应\", issue #1). Loaded by pi\n// via the package.json `pi` manifest (dist/agent/pi.js) or by omp via the\n// config.yml `extensions:` list (dist/agent/omp.js). pi and omp share the\n// ExtensionFactory API shape, so one factory serves both; types below are\n// minimal structural declarations — the bundled artifact imports NOTHING\n// from the host at runtime (the host duck-types us in).\n\nimport { detectProxyBase, fetchManifest, forwardTool, fetchStatus, type ManifestTool } from \"./shared.js\";\n\ntype Ctx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n cwd?: string;\n};\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolResult = { content: TextBlock[]; isError?: boolean };\n\ntype ToolDefinition = {\n name: string;\n description?: string;\n parameters: unknown;\n execute: (toolCallId: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: ((u: unknown) => void) | undefined, ctx: Ctx) => Promise<ToolResult>;\n};\n\ntype CommandCtx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n ui?: { notify?: (message: string, type?: string) => void } | undefined;\n};\n\ntype ExtensionAPI = {\n on: (event: string, handler: (event: never, ctx: Ctx) => unknown) => void;\n registerTool: (tool: ToolDefinition) => void;\n registerCommand?: (name: string, options: { description?: string; handler: (args: string, ctx: CommandCtx) => void | Promise<void> }) => void;\n};\n\nfunction agentName(override: string | undefined): string {\n if (override) return override;\n return process.env.BILLION_CONTEXT_PLUGIN_AGENT === \"omp\" ? \"omp\" : \"pi\";\n}\n\nfunction proxyBaseForCtx(ctx: Ctx): string | undefined {\n return detectProxyBase(ctx.model?.baseUrl);\n}\n\nfunction sessionIdOf(ctx: Ctx): string | undefined {\n try {\n const sid = ctx.sessionManager?.getSessionId?.();\n return typeof sid === \"string\" ? sid : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction fmtTok(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}K`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction renderAcpStatus(s: Record<string, unknown>): string {\n const num = (v: unknown): number | null => (typeof v === \"number\" && Number.isFinite(v) ? v : null);\n const contextTokens = num(s.contextTokens);\n const contextLimit = num(s.contextLimit);\n const inputTokens = num(s.inputTokens);\n const outputTokens = num(s.outputTokens);\n const cachedTokens = num(s.cachedTokens);\n const requests = num(s.requests);\n const blocks = Array.isArray(s.blocks) ? (s.blocks as Array<{ tier?: number; active?: boolean }>) : [];\n const activeBlocks = blocks.filter((b) => b.active === true).length;\n const lines: string[] = [\"📊 ACP status\"];\n if (contextTokens !== null) {\n const pct = contextLimit !== null && contextLimit > 0 ? ` (${((contextTokens / contextLimit) * 100).toFixed(1)}%)` : \"\";\n lines.push(` context: ${fmtTok(contextTokens)}${contextLimit !== null ? ` / ${fmtTok(contextLimit)}` : \"\"}${pct}`);\n }\n if (inputTokens !== null || outputTokens !== null || cachedTokens !== null) {\n lines.push(` in/out/cached: ${fmtTok(inputTokens ?? 0)} / ${fmtTok(outputTokens ?? 0)} / ${fmtTok(cachedTokens ?? 0)}`);\n }\n if (requests !== null) lines.push(` requests: ${requests}`);\n if (blocks.length > 0) lines.push(` blocks: ${blocks.length} (${activeBlocks} active)`);\n return lines.join(\"\\n\");\n}\n\nfunction manifestToTool(proxyBase: string, tool: ManifestTool, agent: string): ToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n try {\n const output = await forwardTool(proxyBase, conversationId, tool.name, params, signal);\n return { content: [{ type: \"text\", text: output }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `bili tool error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n };\n}\n\nconst RETRY_INTERVAL_MS = 10000;\n\ntype RegisterState = { sid?: string; toolsReady?: boolean; pending?: Promise<void>; retryAt?: number };\n\nasync function registerTools(pi: ExtensionAPI, ctx: Ctx, state: RegisterState, agent: string): Promise<void> {\n const proxyBase = proxyBaseForCtx(ctx);\n if (proxyBase === undefined) return;\n // Cache on the session id; \"\" (host has no sessionManager) still caches,\n // so a successful registration is not re-fetched on every provider\n // request — the manifest is session-independent anyway.\n const sid = sessionIdOf(ctx) ?? \"\";\n if (sid === state.sid) return;\n if (state.pending !== undefined) return state.pending;\n if (state.retryAt !== undefined && Date.now() < state.retryAt) return;\n state.pending = (async () => {\n let tools: ManifestTool[];\n try {\n tools = await fetchManifest(proxyBase);\n } catch (err) {\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): manifest fetch failed: ${err instanceof Error ? err.message : String(err)} — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n return;\n }\n try {\n for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));\n state.sid = sid;\n state.toolsReady = true;\n state.retryAt = undefined;\n } catch (err) {\n state.sid = undefined;\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): tool registration deferred (${err instanceof Error ? err.message : String(err)}) — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n }\n })();\n try {\n await state.pending;\n } finally {\n state.pending = undefined;\n }\n}\n\nexport function createBiliPlugin(agentOverride?: string): (pi: ExtensionAPI) => void {\n return function biliPlugin(pi: ExtensionAPI): void {\n const agent = agentName(agentOverride);\n const state: RegisterState = {};\n if (typeof pi.registerCommand === \"function\") {\n pi.registerCommand(\"acp\", {\n description: \"Show ACP context-compression status for this session\",\n handler: async (_args, ctx) => {\n const notify = (message: string, type?: string): void => {\n try {\n ctx.ui?.notify?.(message, type);\n } catch {\n // host UI unavailable — the command is best-effort\n }\n };\n const proxyBase = detectProxyBase(ctx.model?.baseUrl);\n if (proxyBase === undefined) {\n notify(\"bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)\", \"warning\");\n return;\n }\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n let status: Record<string, unknown> | undefined;\n try {\n status = await fetchStatus(proxyBase, conversationId);\n } catch (err) {\n notify(`bili: status fetch failed: ${err instanceof Error ? err.message : String(err)}`, \"error\");\n return;\n }\n if (status === undefined) {\n notify(\"bili: no ACP session yet (send a model request first, then run /acp)\", \"warning\");\n return;\n }\n const panel = typeof status.panel === \"string\" ? status.panel : undefined;\n notify(panel ?? renderAcpStatus(status), \"info\");\n },\n });\n }\n pi.on(\"before_provider_headers\", (event, ctx) => {\n try {\n if (proxyBaseForCtx(ctx) === undefined) return;\n const headers = (event as unknown as { headers?: Record<string, string> }).headers;\n if (headers === undefined || typeof headers !== \"object\" || Array.isArray(headers)) return;\n // The x-bili-plugin marker tells the proxy \"the client owns the\n // ACP tools natively — skip wire-level injection\". Stamping it\n // before registerTools() finishes would send round 1 out with\n // NO ACP tools (the first provider request races the manifest\n // fetch). Claim ownership only once tools are registered;\n // until then the request rides the proxy's wire mode. A\n // permanently failing manifest fetch keeps us in wire mode —\n // a graceful fallback rather than a tool-less session.\n if (state.toolsReady === true) {\n const sid = sessionIdOf(ctx);\n if (sid !== undefined) headers[\"x-bili-plugin-conversation\"] = sid;\n headers[\"x-bili-plugin\"] = agent;\n const window = ctx.model?.contextWindow;\n if (typeof window === \"number\" && Number.isFinite(window) && window > 0) {\n headers[\"x-bili-plugin-context-window\"] = String(Math.floor(window));\n }\n }\n } catch (err) {\n console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);\n }\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n pi.on(\"session_start\", (_event, ctx) => {\n state.sid = undefined;\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n };\n}\n\nexport default createBiliPlugin();\n\nexport { fetchStatus };\n","import { createBiliPlugin } from \"./pi.js\";\n\nexport default createBiliPlugin(\"omp\");\n"],"mappings":"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","names":[]}
|
package/dist/agent/pi.js
CHANGED
|
@@ -165,6 +165,7 @@ async function registerTools(pi, ctx, state, agent) {
|
|
|
165
165
|
try {
|
|
166
166
|
for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));
|
|
167
167
|
state.sid = sid;
|
|
168
|
+
state.toolsReady = true;
|
|
168
169
|
state.retryAt = void 0;
|
|
169
170
|
} catch (err) {
|
|
170
171
|
state.sid = void 0;
|
|
@@ -219,12 +220,14 @@ function createBiliPlugin(agentOverride) {
|
|
|
219
220
|
if (proxyBaseForCtx(ctx) === void 0) return;
|
|
220
221
|
const headers = event.headers;
|
|
221
222
|
if (headers === void 0 || typeof headers !== "object" || Array.isArray(headers)) return;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
if (state.toolsReady === true) {
|
|
224
|
+
const sid = sessionIdOf(ctx);
|
|
225
|
+
if (sid !== void 0) headers["x-bili-plugin-conversation"] = sid;
|
|
226
|
+
headers["x-bili-plugin"] = agent;
|
|
227
|
+
const window = ctx.model?.contextWindow;
|
|
228
|
+
if (typeof window === "number" && Number.isFinite(window) && window > 0) {
|
|
229
|
+
headers["x-bili-plugin-context-window"] = String(Math.floor(window));
|
|
230
|
+
}
|
|
228
231
|
}
|
|
229
232
|
} catch (err) {
|
|
230
233
|
console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);
|
package/dist/agent/pi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/shared.ts","../../src/agent/pi.ts"],"sourcesContent":["// Shared thin-plugin core for agent-side extensions (\"内外呼应\", issue #1).\n// The agent plugin is a PURE PROTOCOL CLIENT: no acp-kernel import, no\n// compression logic. The proxy stays the single compression authority; the\n// plugin only (1) detects the proxy, (2) fetches the tool manifest (single\n// source of truth), (3) forwards tool executes, (4) reads status. Same\n// package as the proxy ⇒ same version ⇒ no kernel-skew bug class.\n\nexport type ManifestTool = {\n name: string;\n description?: string;\n inputSchema: unknown;\n};\n\nconst MANIFEST_TIMEOUT_MS = 5000;\nconst TOOL_TIMEOUT_MS = 60000;\nconst STATUS_TIMEOUT_MS = 5000;\n\n/** Detect the proxy from a provider baseUrl's `/bili/` zero-config prefix.\n * The real prefix embeds the full upstream URL (`/bili/https://…`), so the\n * check requires `bili` as the first path segment followed by an http(s)\n * URL — a plain `/foo/bili/` path segment is NOT a bili proxy.\n * Returns the proxy origin (scheme//host) the request will actually hit. */\nexport function proxyBaseFromUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined;\n try {\n const url = new URL(baseUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n const segments = url.pathname.split(\"/\").filter((s) => s.length > 0);\n if (segments[0] !== \"bili\") return undefined;\n const rest = url.pathname.slice(url.pathname.indexOf(\"bili\") + \"bili\".length);\n if (!/^\\/https?:\\/\\//.test(rest)) return undefined;\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\n/** MITM transparent mode has no `/bili/` prefix; the proxy's launcher exports\n * BILLION_CONTEXT_PROXY. A stale value surfaces as a tool-forward error. */\nexport function proxyBaseFromEnv(): string | undefined {\n const raw = process.env.BILLION_CONTEXT_PROXY?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? `${url.protocol}//${url.host}` : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function detectProxyBase(baseUrl: string | undefined): string | undefined {\n if (process.env.BILLION_CONTEXT_PLUGIN === \"0\") return undefined;\n return proxyBaseFromUrl(baseUrl) ?? proxyBaseFromEnv();\n}\n\nasync function fetchJson(url: string, init: RequestInit | undefined, timeoutMs: number, externalSignal?: AbortSignal): Promise<{ ok: boolean; status: number; json: unknown }> {\n const ac = new AbortController();\n // An already-aborted external signal never fires its \"abort\" event, so\n // forward the state directly — otherwise only the timeout could stop\n // the request, turning an instant cancel into a timeout wait.\n if (externalSignal?.aborted) ac.abort();\n const timer = setTimeout(() => ac.abort(), timeoutMs);\n const onExternalAbort = () => ac.abort();\n externalSignal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n try {\n let res: Response;\n try {\n res = await fetch(url, { ...init, signal: ac.signal });\n } catch (err) {\n if (ac.signal.aborted && !externalSignal?.aborted) throw new Error(`timeout after ${timeoutMs}ms: ${url}`);\n throw err;\n }\n const text = await res.text();\n let json: unknown = undefined;\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json };\n } finally {\n clearTimeout(timer);\n externalSignal?.removeEventListener(\"abort\", onExternalAbort);\n }\n}\n\nexport async function fetchManifest(proxyBase: string): Promise<ManifestTool[]> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/manifest`, undefined, MANIFEST_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") throw new Error(`manifest fetch failed: ${status}`);\n const data = json as { tools?: { anthropic?: { name?: string; description?: string; input_schema?: unknown }[] } };\n const tools = (data.tools?.anthropic ?? []).filter((t): t is { name: string; description?: string; input_schema?: unknown } => typeof t.name === \"string\");\n if (tools.length === 0) throw new Error(\"manifest served no anthropic tools\");\n return tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.input_schema ?? { type: \"object\", properties: {} } }));\n}\n\nexport async function forwardTool(proxyBase: string, conversationId: string, tool: string, args: unknown, signal?: AbortSignal): Promise<string> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/tool`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ conversationId, tool, args: args ?? {} }),\n }, TOOL_TIMEOUT_MS, signal);\n const data = json as { ok?: boolean; result?: string; error?: string } | undefined;\n if (!ok || !data?.ok) {\n throw new Error(`bili proxy tool ${tool} failed (${status}): ${data?.error ?? \"unknown error\"}`);\n }\n return data.result ?? \"\";\n}\n\n/** Soft-fail by design: the status read is best-effort UI data; undefined\n * means \"no data\" whether the proxy is down or the session is unknown. */\nexport async function fetchStatus(proxyBase: string, conversationId: string): Promise<Record<string, unknown> | undefined> {\n const { ok, json } = await fetchJson(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId)}`, undefined, STATUS_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") return undefined;\n return json as Record<string, unknown>;\n}\n","// Thin agent extension for pi and omp (\"内外呼应\", issue #1). Loaded by pi\n// via the package.json `pi` manifest (dist/agent/pi.js) or by omp via the\n// config.yml `extensions:` list (dist/agent/omp.js). pi and omp share the\n// ExtensionFactory API shape, so one factory serves both; types below are\n// minimal structural declarations — the bundled artifact imports NOTHING\n// from the host at runtime (the host duck-types us in).\n\nimport { detectProxyBase, fetchManifest, forwardTool, fetchStatus, type ManifestTool } from \"./shared.js\";\n\ntype Ctx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n cwd?: string;\n};\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolResult = { content: TextBlock[]; isError?: boolean };\n\ntype ToolDefinition = {\n name: string;\n description?: string;\n parameters: unknown;\n execute: (toolCallId: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: ((u: unknown) => void) | undefined, ctx: Ctx) => Promise<ToolResult>;\n};\n\ntype CommandCtx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n ui?: { notify?: (message: string, type?: string) => void } | undefined;\n};\n\ntype ExtensionAPI = {\n on: (event: string, handler: (event: never, ctx: Ctx) => unknown) => void;\n registerTool: (tool: ToolDefinition) => void;\n registerCommand?: (name: string, options: { description?: string; handler: (args: string, ctx: CommandCtx) => void | Promise<void> }) => void;\n};\n\nfunction agentName(override: string | undefined): string {\n if (override) return override;\n return process.env.BILLION_CONTEXT_PLUGIN_AGENT === \"omp\" ? \"omp\" : \"pi\";\n}\n\nfunction proxyBaseForCtx(ctx: Ctx): string | undefined {\n return detectProxyBase(ctx.model?.baseUrl);\n}\n\nfunction sessionIdOf(ctx: Ctx): string | undefined {\n try {\n const sid = ctx.sessionManager?.getSessionId?.();\n return typeof sid === \"string\" ? sid : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction fmtTok(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}K`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction renderAcpStatus(s: Record<string, unknown>): string {\n const num = (v: unknown): number | null => (typeof v === \"number\" && Number.isFinite(v) ? v : null);\n const contextTokens = num(s.contextTokens);\n const contextLimit = num(s.contextLimit);\n const inputTokens = num(s.inputTokens);\n const outputTokens = num(s.outputTokens);\n const cachedTokens = num(s.cachedTokens);\n const requests = num(s.requests);\n const blocks = Array.isArray(s.blocks) ? (s.blocks as Array<{ tier?: number; active?: boolean }>) : [];\n const activeBlocks = blocks.filter((b) => b.active === true).length;\n const lines: string[] = [\"📊 ACP status\"];\n if (contextTokens !== null) {\n const pct = contextLimit !== null && contextLimit > 0 ? ` (${((contextTokens / contextLimit) * 100).toFixed(1)}%)` : \"\";\n lines.push(` context: ${fmtTok(contextTokens)}${contextLimit !== null ? ` / ${fmtTok(contextLimit)}` : \"\"}${pct}`);\n }\n if (inputTokens !== null || outputTokens !== null || cachedTokens !== null) {\n lines.push(` in/out/cached: ${fmtTok(inputTokens ?? 0)} / ${fmtTok(outputTokens ?? 0)} / ${fmtTok(cachedTokens ?? 0)}`);\n }\n if (requests !== null) lines.push(` requests: ${requests}`);\n if (blocks.length > 0) lines.push(` blocks: ${blocks.length} (${activeBlocks} active)`);\n return lines.join(\"\\n\");\n}\n\nfunction manifestToTool(proxyBase: string, tool: ManifestTool, agent: string): ToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n try {\n const output = await forwardTool(proxyBase, conversationId, tool.name, params, signal);\n return { content: [{ type: \"text\", text: output }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `bili tool error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n };\n}\n\nconst RETRY_INTERVAL_MS = 10000;\n\ntype RegisterState = { sid?: string; pending?: Promise<void>; retryAt?: number };\n\nasync function registerTools(pi: ExtensionAPI, ctx: Ctx, state: RegisterState, agent: string): Promise<void> {\n const proxyBase = proxyBaseForCtx(ctx);\n if (proxyBase === undefined) return;\n // Cache on the session id; \"\" (host has no sessionManager) still caches,\n // so a successful registration is not re-fetched on every provider\n // request — the manifest is session-independent anyway.\n const sid = sessionIdOf(ctx) ?? \"\";\n if (sid === state.sid) return;\n if (state.pending !== undefined) return state.pending;\n if (state.retryAt !== undefined && Date.now() < state.retryAt) return;\n state.pending = (async () => {\n let tools: ManifestTool[];\n try {\n tools = await fetchManifest(proxyBase);\n } catch (err) {\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): manifest fetch failed: ${err instanceof Error ? err.message : String(err)} — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n return;\n }\n try {\n for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));\n state.sid = sid;\n state.retryAt = undefined;\n } catch (err) {\n state.sid = undefined;\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): tool registration deferred (${err instanceof Error ? err.message : String(err)}) — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n }\n })();\n try {\n await state.pending;\n } finally {\n state.pending = undefined;\n }\n}\n\nexport function createBiliPlugin(agentOverride?: string): (pi: ExtensionAPI) => void {\n return function biliPlugin(pi: ExtensionAPI): void {\n const agent = agentName(agentOverride);\n const state: RegisterState = {};\n if (typeof pi.registerCommand === \"function\") {\n pi.registerCommand(\"acp\", {\n description: \"Show ACP context-compression status for this session\",\n handler: async (_args, ctx) => {\n const notify = (message: string, type?: string): void => {\n try {\n ctx.ui?.notify?.(message, type);\n } catch {\n // host UI unavailable — the command is best-effort\n }\n };\n const proxyBase = detectProxyBase(ctx.model?.baseUrl);\n if (proxyBase === undefined) {\n notify(\"bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)\", \"warning\");\n return;\n }\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n let status: Record<string, unknown> | undefined;\n try {\n status = await fetchStatus(proxyBase, conversationId);\n } catch (err) {\n notify(`bili: status fetch failed: ${err instanceof Error ? err.message : String(err)}`, \"error\");\n return;\n }\n if (status === undefined) {\n notify(\"bili: no ACP session yet (send a model request first, then run /acp)\", \"warning\");\n return;\n }\n const panel = typeof status.panel === \"string\" ? status.panel : undefined;\n notify(panel ?? renderAcpStatus(status), \"info\");\n },\n });\n }\n pi.on(\"before_provider_headers\", (event, ctx) => {\n try {\n if (proxyBaseForCtx(ctx) === undefined) return;\n const headers = (event as unknown as { headers?: Record<string, string> }).headers;\n if (headers === undefined || typeof headers !== \"object\" || Array.isArray(headers)) return;\n const sid = sessionIdOf(ctx);\n if (sid !== undefined) headers[\"x-bili-plugin-conversation\"] = sid;\n headers[\"x-bili-plugin\"] = agent;\n const window = ctx.model?.contextWindow;\n if (typeof window === \"number\" && Number.isFinite(window) && window > 0) {\n headers[\"x-bili-plugin-context-window\"] = String(Math.floor(window));\n }\n } catch (err) {\n console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);\n }\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n pi.on(\"session_start\", (_event, ctx) => {\n state.sid = undefined;\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n };\n}\n\nexport default createBiliPlugin();\n\nexport { fetchStatus };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/shared.ts","../../src/agent/pi.ts"],"sourcesContent":["// Shared thin-plugin core for agent-side extensions (\"内外呼应\", issue #1).\n// The agent plugin is a PURE PROTOCOL CLIENT: no acp-kernel import, no\n// compression logic. The proxy stays the single compression authority; the\n// plugin only (1) detects the proxy, (2) fetches the tool manifest (single\n// source of truth), (3) forwards tool executes, (4) reads status. Same\n// package as the proxy ⇒ same version ⇒ no kernel-skew bug class.\n\nexport type ManifestTool = {\n name: string;\n description?: string;\n inputSchema: unknown;\n};\n\nconst MANIFEST_TIMEOUT_MS = 5000;\nconst TOOL_TIMEOUT_MS = 60000;\nconst STATUS_TIMEOUT_MS = 5000;\n\n/** Detect the proxy from a provider baseUrl's `/bili/` zero-config prefix.\n * The real prefix embeds the full upstream URL (`/bili/https://…`), so the\n * check requires `bili` as the first path segment followed by an http(s)\n * URL — a plain `/foo/bili/` path segment is NOT a bili proxy.\n * Returns the proxy origin (scheme//host) the request will actually hit. */\nexport function proxyBaseFromUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined;\n try {\n const url = new URL(baseUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n const segments = url.pathname.split(\"/\").filter((s) => s.length > 0);\n if (segments[0] !== \"bili\") return undefined;\n const rest = url.pathname.slice(url.pathname.indexOf(\"bili\") + \"bili\".length);\n if (!/^\\/https?:\\/\\//.test(rest)) return undefined;\n return `${url.protocol}//${url.host}`;\n } catch {\n return undefined;\n }\n}\n\n/** MITM transparent mode has no `/bili/` prefix; the proxy's launcher exports\n * BILLION_CONTEXT_PROXY. A stale value surfaces as a tool-forward error. */\nexport function proxyBaseFromEnv(): string | undefined {\n const raw = process.env.BILLION_CONTEXT_PROXY?.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? `${url.protocol}//${url.host}` : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function detectProxyBase(baseUrl: string | undefined): string | undefined {\n if (process.env.BILLION_CONTEXT_PLUGIN === \"0\") return undefined;\n return proxyBaseFromUrl(baseUrl) ?? proxyBaseFromEnv();\n}\n\nasync function fetchJson(url: string, init: RequestInit | undefined, timeoutMs: number, externalSignal?: AbortSignal): Promise<{ ok: boolean; status: number; json: unknown }> {\n const ac = new AbortController();\n // An already-aborted external signal never fires its \"abort\" event, so\n // forward the state directly — otherwise only the timeout could stop\n // the request, turning an instant cancel into a timeout wait.\n if (externalSignal?.aborted) ac.abort();\n const timer = setTimeout(() => ac.abort(), timeoutMs);\n const onExternalAbort = () => ac.abort();\n externalSignal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n try {\n let res: Response;\n try {\n res = await fetch(url, { ...init, signal: ac.signal });\n } catch (err) {\n if (ac.signal.aborted && !externalSignal?.aborted) throw new Error(`timeout after ${timeoutMs}ms: ${url}`);\n throw err;\n }\n const text = await res.text();\n let json: unknown = undefined;\n try {\n json = JSON.parse(text);\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json };\n } finally {\n clearTimeout(timer);\n externalSignal?.removeEventListener(\"abort\", onExternalAbort);\n }\n}\n\nexport async function fetchManifest(proxyBase: string): Promise<ManifestTool[]> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/manifest`, undefined, MANIFEST_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") throw new Error(`manifest fetch failed: ${status}`);\n const data = json as { tools?: { anthropic?: { name?: string; description?: string; input_schema?: unknown }[] } };\n const tools = (data.tools?.anthropic ?? []).filter((t): t is { name: string; description?: string; input_schema?: unknown } => typeof t.name === \"string\");\n if (tools.length === 0) throw new Error(\"manifest served no anthropic tools\");\n return tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.input_schema ?? { type: \"object\", properties: {} } }));\n}\n\nexport async function forwardTool(proxyBase: string, conversationId: string, tool: string, args: unknown, signal?: AbortSignal): Promise<string> {\n const { ok, status, json } = await fetchJson(`${proxyBase}/__bili/plugin/tool`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ conversationId, tool, args: args ?? {} }),\n }, TOOL_TIMEOUT_MS, signal);\n const data = json as { ok?: boolean; result?: string; error?: string } | undefined;\n if (!ok || !data?.ok) {\n throw new Error(`bili proxy tool ${tool} failed (${status}): ${data?.error ?? \"unknown error\"}`);\n }\n return data.result ?? \"\";\n}\n\n/** Soft-fail by design: the status read is best-effort UI data; undefined\n * means \"no data\" whether the proxy is down or the session is unknown. */\nexport async function fetchStatus(proxyBase: string, conversationId: string): Promise<Record<string, unknown> | undefined> {\n const { ok, json } = await fetchJson(`${proxyBase}/__bili/plugin/status?conversationId=${encodeURIComponent(conversationId)}`, undefined, STATUS_TIMEOUT_MS);\n if (!ok || !json || typeof json !== \"object\") return undefined;\n return json as Record<string, unknown>;\n}\n","// Thin agent extension for pi and omp (\"内外呼应\", issue #1). Loaded by pi\n// via the package.json `pi` manifest (dist/agent/pi.js) or by omp via the\n// config.yml `extensions:` list (dist/agent/omp.js). pi and omp share the\n// ExtensionFactory API shape, so one factory serves both; types below are\n// minimal structural declarations — the bundled artifact imports NOTHING\n// from the host at runtime (the host duck-types us in).\n\nimport { detectProxyBase, fetchManifest, forwardTool, fetchStatus, type ManifestTool } from \"./shared.js\";\n\ntype Ctx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n cwd?: string;\n};\n\ntype TextBlock = { type: \"text\"; text: string };\ntype ToolResult = { content: TextBlock[]; isError?: boolean };\n\ntype ToolDefinition = {\n name: string;\n description?: string;\n parameters: unknown;\n execute: (toolCallId: string, params: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: ((u: unknown) => void) | undefined, ctx: Ctx) => Promise<ToolResult>;\n};\n\ntype CommandCtx = {\n sessionManager?: { getSessionId?: () => string } | undefined;\n model?: { contextWindow?: number; baseUrl?: string } | undefined;\n ui?: { notify?: (message: string, type?: string) => void } | undefined;\n};\n\ntype ExtensionAPI = {\n on: (event: string, handler: (event: never, ctx: Ctx) => unknown) => void;\n registerTool: (tool: ToolDefinition) => void;\n registerCommand?: (name: string, options: { description?: string; handler: (args: string, ctx: CommandCtx) => void | Promise<void> }) => void;\n};\n\nfunction agentName(override: string | undefined): string {\n if (override) return override;\n return process.env.BILLION_CONTEXT_PLUGIN_AGENT === \"omp\" ? \"omp\" : \"pi\";\n}\n\nfunction proxyBaseForCtx(ctx: Ctx): string | undefined {\n return detectProxyBase(ctx.model?.baseUrl);\n}\n\nfunction sessionIdOf(ctx: Ctx): string | undefined {\n try {\n const sid = ctx.sessionManager?.getSessionId?.();\n return typeof sid === \"string\" ? sid : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction fmtTok(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(1)}K`;\n return `${(n / 1_000_000).toFixed(2)}M`;\n}\n\nfunction renderAcpStatus(s: Record<string, unknown>): string {\n const num = (v: unknown): number | null => (typeof v === \"number\" && Number.isFinite(v) ? v : null);\n const contextTokens = num(s.contextTokens);\n const contextLimit = num(s.contextLimit);\n const inputTokens = num(s.inputTokens);\n const outputTokens = num(s.outputTokens);\n const cachedTokens = num(s.cachedTokens);\n const requests = num(s.requests);\n const blocks = Array.isArray(s.blocks) ? (s.blocks as Array<{ tier?: number; active?: boolean }>) : [];\n const activeBlocks = blocks.filter((b) => b.active === true).length;\n const lines: string[] = [\"📊 ACP status\"];\n if (contextTokens !== null) {\n const pct = contextLimit !== null && contextLimit > 0 ? ` (${((contextTokens / contextLimit) * 100).toFixed(1)}%)` : \"\";\n lines.push(` context: ${fmtTok(contextTokens)}${contextLimit !== null ? ` / ${fmtTok(contextLimit)}` : \"\"}${pct}`);\n }\n if (inputTokens !== null || outputTokens !== null || cachedTokens !== null) {\n lines.push(` in/out/cached: ${fmtTok(inputTokens ?? 0)} / ${fmtTok(outputTokens ?? 0)} / ${fmtTok(cachedTokens ?? 0)}`);\n }\n if (requests !== null) lines.push(` requests: ${requests}`);\n if (blocks.length > 0) lines.push(` blocks: ${blocks.length} (${activeBlocks} active)`);\n return lines.join(\"\\n\");\n}\n\nfunction manifestToTool(proxyBase: string, tool: ManifestTool, agent: string): ToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n try {\n const output = await forwardTool(proxyBase, conversationId, tool.name, params, signal);\n return { content: [{ type: \"text\", text: output }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `bili tool error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n };\n}\n\nconst RETRY_INTERVAL_MS = 10000;\n\ntype RegisterState = { sid?: string; toolsReady?: boolean; pending?: Promise<void>; retryAt?: number };\n\nasync function registerTools(pi: ExtensionAPI, ctx: Ctx, state: RegisterState, agent: string): Promise<void> {\n const proxyBase = proxyBaseForCtx(ctx);\n if (proxyBase === undefined) return;\n // Cache on the session id; \"\" (host has no sessionManager) still caches,\n // so a successful registration is not re-fetched on every provider\n // request — the manifest is session-independent anyway.\n const sid = sessionIdOf(ctx) ?? \"\";\n if (sid === state.sid) return;\n if (state.pending !== undefined) return state.pending;\n if (state.retryAt !== undefined && Date.now() < state.retryAt) return;\n state.pending = (async () => {\n let tools: ManifestTool[];\n try {\n tools = await fetchManifest(proxyBase);\n } catch (err) {\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): manifest fetch failed: ${err instanceof Error ? err.message : String(err)} — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n return;\n }\n try {\n for (const t of tools) pi.registerTool(manifestToTool(proxyBase, t, agent));\n state.sid = sid;\n state.toolsReady = true;\n state.retryAt = undefined;\n } catch (err) {\n state.sid = undefined;\n state.retryAt = Date.now() + RETRY_INTERVAL_MS;\n console.error(`bili-plugin(${agent}): tool registration deferred (${err instanceof Error ? err.message : String(err)}) — retrying in ${RETRY_INTERVAL_MS / 1000}s`);\n }\n })();\n try {\n await state.pending;\n } finally {\n state.pending = undefined;\n }\n}\n\nexport function createBiliPlugin(agentOverride?: string): (pi: ExtensionAPI) => void {\n return function biliPlugin(pi: ExtensionAPI): void {\n const agent = agentName(agentOverride);\n const state: RegisterState = {};\n if (typeof pi.registerCommand === \"function\") {\n pi.registerCommand(\"acp\", {\n description: \"Show ACP context-compression status for this session\",\n handler: async (_args, ctx) => {\n const notify = (message: string, type?: string): void => {\n try {\n ctx.ui?.notify?.(message, type);\n } catch {\n // host UI unavailable — the command is best-effort\n }\n };\n const proxyBase = detectProxyBase(ctx.model?.baseUrl);\n if (proxyBase === undefined) {\n notify(\"bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)\", \"warning\");\n return;\n }\n const conversationId = sessionIdOf(ctx) ?? \"unknown\";\n let status: Record<string, unknown> | undefined;\n try {\n status = await fetchStatus(proxyBase, conversationId);\n } catch (err) {\n notify(`bili: status fetch failed: ${err instanceof Error ? err.message : String(err)}`, \"error\");\n return;\n }\n if (status === undefined) {\n notify(\"bili: no ACP session yet (send a model request first, then run /acp)\", \"warning\");\n return;\n }\n const panel = typeof status.panel === \"string\" ? status.panel : undefined;\n notify(panel ?? renderAcpStatus(status), \"info\");\n },\n });\n }\n pi.on(\"before_provider_headers\", (event, ctx) => {\n try {\n if (proxyBaseForCtx(ctx) === undefined) return;\n const headers = (event as unknown as { headers?: Record<string, string> }).headers;\n if (headers === undefined || typeof headers !== \"object\" || Array.isArray(headers)) return;\n // The x-bili-plugin marker tells the proxy \"the client owns the\n // ACP tools natively — skip wire-level injection\". Stamping it\n // before registerTools() finishes would send round 1 out with\n // NO ACP tools (the first provider request races the manifest\n // fetch). Claim ownership only once tools are registered;\n // until then the request rides the proxy's wire mode. A\n // permanently failing manifest fetch keeps us in wire mode —\n // a graceful fallback rather than a tool-less session.\n if (state.toolsReady === true) {\n const sid = sessionIdOf(ctx);\n if (sid !== undefined) headers[\"x-bili-plugin-conversation\"] = sid;\n headers[\"x-bili-plugin\"] = agent;\n const window = ctx.model?.contextWindow;\n if (typeof window === \"number\" && Number.isFinite(window) && window > 0) {\n headers[\"x-bili-plugin-context-window\"] = String(Math.floor(window));\n }\n }\n } catch (err) {\n console.error(`bili-plugin(${agent}): header stamp skipped (${err instanceof Error ? err.message : String(err)})`);\n }\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n pi.on(\"session_start\", (_event, ctx) => {\n state.sid = undefined;\n void registerTools(pi, ctx, state, agent).catch((err: unknown) => console.error(`bili-plugin(${agent}): ${err instanceof Error ? err.message : String(err)}`));\n });\n };\n}\n\nexport default createBiliPlugin();\n\nexport { fetchStatus };\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -47346,7 +47346,8 @@ var CONTEXT_LIMIT_TABLE = [
|
|
|
47346
47346
|
{ match: /^glm-4\.6/i, limit: 128e3 },
|
|
47347
47347
|
{ match: /^glm-5/i, limit: 1e6 },
|
|
47348
47348
|
{ match: /^glm-/i, limit: 128e3 },
|
|
47349
|
-
{ match: /^deepseek/i, limit:
|
|
47349
|
+
{ match: /^deepseek/i, limit: 128e3 },
|
|
47350
|
+
{ match: /^minimax/i, limit: 204800 },
|
|
47350
47351
|
{ match: /^qwen/i, limit: 128e3 },
|
|
47351
47352
|
{ match: /^kimi/i, limit: 128e3 },
|
|
47352
47353
|
{ match: /^llama-/i, limit: 128e3 }
|
|
@@ -47800,7 +47801,10 @@ var HOST_TO_PROVIDER = {
|
|
|
47800
47801
|
"api.deepseek.com": "deepseek",
|
|
47801
47802
|
"api.moonshot.cn": "moonshot",
|
|
47802
47803
|
"generativelanguage.googleapis.com": "google",
|
|
47803
|
-
"ai.comfly.org": "comfly"
|
|
47804
|
+
"ai.comfly.org": "comfly",
|
|
47805
|
+
"api.minimax.chat": "minimax",
|
|
47806
|
+
"api.minimaxi.com": "minimax",
|
|
47807
|
+
"api.minimax.io": "minimax"
|
|
47804
47808
|
};
|
|
47805
47809
|
function providerFromHost(host) {
|
|
47806
47810
|
const lower = host.toLowerCase();
|
|
@@ -47812,6 +47816,12 @@ function providerFromHost(host) {
|
|
|
47812
47816
|
}
|
|
47813
47817
|
async function contextFromRegistry(model, host) {
|
|
47814
47818
|
const reg = await loadRegistry();
|
|
47819
|
+
return registryLookup(reg, model, host);
|
|
47820
|
+
}
|
|
47821
|
+
function peekRegistryContext(model, host) {
|
|
47822
|
+
return registryLookup(cache2, model, host);
|
|
47823
|
+
}
|
|
47824
|
+
function registryLookup(reg, model, host) {
|
|
47815
47825
|
if (!reg || !model) return void 0;
|
|
47816
47826
|
const provider = host ? providerFromHost(host) : void 0;
|
|
47817
47827
|
const candidates = provider ? [`${provider}/${model}`, model] : [model];
|
|
@@ -49487,7 +49497,7 @@ function busy(button,on,label){if(!button)return;if(on){button.dataset.label=but
|
|
|
49487
49497
|
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}
|
|
49488
49498
|
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()}}
|
|
49489
49499
|
document.querySelectorAll(".nav button").forEach((button)=>button.addEventListener("click",()=>showPage(button.dataset.page)));
|
|
49490
|
-
async function loadConfig(){const data=await json("/__bili/config");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}
|
|
49500
|
+
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}
|
|
49491
49501
|
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)}}
|
|
49492
49502
|
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)}}
|
|
49493
49503
|
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)}}
|
|
@@ -49532,13 +49542,19 @@ function renderPage(origin, version2) {
|
|
|
49532
49542
|
}
|
|
49533
49543
|
|
|
49534
49544
|
// src/web/api.ts
|
|
49535
|
-
import { closeSync, fsyncSync, mkdirSync as mkdirSync4, openSync, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
49545
|
+
import { closeSync, existsSync as existsSync3, fsyncSync, mkdirSync as mkdirSync4, openSync, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
49536
49546
|
import { dirname as dirname3 } from "path";
|
|
49537
49547
|
import { randomUUID } from "crypto";
|
|
49538
49548
|
function readConfig() {
|
|
49539
49549
|
const parsed = safeReadJson(configFile());
|
|
49540
49550
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
49541
49551
|
}
|
|
49552
|
+
function configParseError() {
|
|
49553
|
+
if (!existsSync3(configFile())) return null;
|
|
49554
|
+
const parsed = safeReadJson(configFile());
|
|
49555
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return null;
|
|
49556
|
+
return `config file is not valid JSON: ${configFile()}`;
|
|
49557
|
+
}
|
|
49542
49558
|
function readProviders() {
|
|
49543
49559
|
return loadRoutes();
|
|
49544
49560
|
}
|
|
@@ -49574,18 +49590,23 @@ function atomicWriteConfig(config) {
|
|
|
49574
49590
|
async function handleConfigGet(res) {
|
|
49575
49591
|
const upstream = readUpstreamSettings();
|
|
49576
49592
|
const config = readConfig();
|
|
49593
|
+
const parseError = configParseError();
|
|
49594
|
+
if (parseError) log("warn", `[acp-web] ${parseError} \u2014 showing empty view; PUT is blocked until fixed`);
|
|
49577
49595
|
res.writeHead(200, { "content-type": "application/json" });
|
|
49578
49596
|
res.end(JSON.stringify({
|
|
49579
49597
|
path: configFile(),
|
|
49580
49598
|
providers: readProviders(),
|
|
49581
49599
|
upstreamProxy: upstream.proxy ?? null,
|
|
49582
49600
|
upstreamProxyMode: upstream.mode,
|
|
49583
|
-
compress: config.compress ?? null
|
|
49601
|
+
compress: config.compress ?? null,
|
|
49602
|
+
...parseError ? { parseError } : {}
|
|
49584
49603
|
}, null, 2));
|
|
49585
49604
|
}
|
|
49586
49605
|
async function handleConfigPut(req, res, onChanged, biliPort = 8787) {
|
|
49587
49606
|
const raw = await readJsonBody(req);
|
|
49588
49607
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return sendError(res, 400, "expected JSON object");
|
|
49608
|
+
const parseError = configParseError();
|
|
49609
|
+
if (parseError) return sendError(res, 409, `${parseError} \u2014 fix the syntax error by hand, then retry; refusing to overwrite`);
|
|
49589
49610
|
const body = raw;
|
|
49590
49611
|
const hasProviders = Object.prototype.hasOwnProperty.call(body, "providers");
|
|
49591
49612
|
const hasProxy = Object.prototype.hasOwnProperty.call(body, "upstreamProxy");
|
|
@@ -50048,6 +50069,19 @@ async function* runCompressLoop(upstream, ctx, requestBody, requestOptions, adap
|
|
|
50048
50069
|
}
|
|
50049
50070
|
|
|
50050
50071
|
// src/loop/adapter-responses.ts
|
|
50072
|
+
function rewriteItemEvent(type, obj, mapped) {
|
|
50073
|
+
const item = { ...obj.item ?? {}, id: mapped.id };
|
|
50074
|
+
return Buffer.from(`event: ${type}
|
|
50075
|
+
data: ${JSON.stringify({ ...obj, output_index: mapped.index, item })}
|
|
50076
|
+
|
|
50077
|
+
`, "utf8");
|
|
50078
|
+
}
|
|
50079
|
+
function rewriteRefEvent(type, obj, mapped) {
|
|
50080
|
+
return Buffer.from(`event: ${type}
|
|
50081
|
+
data: ${JSON.stringify({ ...obj, item_id: mapped.id, output_index: mapped.index })}
|
|
50082
|
+
|
|
50083
|
+
`, "utf8");
|
|
50084
|
+
}
|
|
50051
50085
|
async function* iterSseEvents(stream2) {
|
|
50052
50086
|
const reader = stream2.getReader();
|
|
50053
50087
|
let buf = "";
|
|
@@ -50213,6 +50247,7 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
50213
50247
|
},
|
|
50214
50248
|
async *parseStream(upstream, round) {
|
|
50215
50249
|
const pending = /* @__PURE__ */ new Map();
|
|
50250
|
+
const remapped = /* @__PURE__ */ new Map();
|
|
50216
50251
|
for await (const eventStr of iterSseEvents(upstream)) {
|
|
50217
50252
|
const type = extractEventType(eventStr);
|
|
50218
50253
|
const dataLine = extractDataLine(eventStr);
|
|
@@ -50246,17 +50281,32 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
50246
50281
|
}
|
|
50247
50282
|
} else if (item?.type === "custom_tool_call") {
|
|
50248
50283
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: false };
|
|
50284
|
+
} else if (item?.type === "message" && round > 1 && !suppressTextLifecycle) {
|
|
50285
|
+
const origId = typeof item.id === "string" ? item.id : "";
|
|
50286
|
+
const mapped = { id: `msg-proxy-${round}-${origId || outputIndex}`, index: outputIndex++ };
|
|
50287
|
+
if (origId) remapped.set(origId, mapped);
|
|
50288
|
+
yield { kind: "meta", chunk: rewriteItemEvent(type, obj, mapped), firstRoundOnly: false };
|
|
50249
50289
|
} else if (item?.type !== "message" || !suppressTextLifecycle) {
|
|
50250
50290
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
50251
50291
|
}
|
|
50252
50292
|
} else if (type === "response.content_part.added" || type === "response.content_part.done" || type === "response.output_text.done") {
|
|
50253
|
-
|
|
50293
|
+
const mapped = remapped.get(typeof obj.item_id === "string" ? obj.item_id : "");
|
|
50294
|
+
if (mapped) {
|
|
50295
|
+
yield { kind: "meta", chunk: rewriteRefEvent(type, obj, mapped), firstRoundOnly: false };
|
|
50296
|
+
} else if (!suppressTextLifecycle) {
|
|
50254
50297
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
50255
50298
|
}
|
|
50256
50299
|
} else if (type === "response.output_text.delta") {
|
|
50257
50300
|
const delta = typeof obj.delta === "string" ? obj.delta : "";
|
|
50258
50301
|
if (delta.length > 0) {
|
|
50259
|
-
|
|
50302
|
+
const mapped = remapped.get(typeof obj.item_id === "string" ? obj.item_id : "");
|
|
50303
|
+
if (mapped) {
|
|
50304
|
+
yield { kind: "text", delta, raw: rewriteRefEvent(type, obj, mapped) };
|
|
50305
|
+
} else if (round === 1) {
|
|
50306
|
+
yield { kind: "text", delta, raw: rawBuf };
|
|
50307
|
+
} else {
|
|
50308
|
+
yield { kind: "text", delta };
|
|
50309
|
+
}
|
|
50260
50310
|
}
|
|
50261
50311
|
} else if (type === "response.function_call_arguments.delta") {
|
|
50262
50312
|
const itemId = typeof obj.item_id === "string" ? obj.item_id : "";
|
|
@@ -50296,6 +50346,15 @@ function createResponsesAdapter(textProtocol, projection) {
|
|
|
50296
50346
|
}
|
|
50297
50347
|
} else if (item?.type === "custom_tool_call") {
|
|
50298
50348
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: false };
|
|
50349
|
+
} else if (item?.type === "message") {
|
|
50350
|
+
const origId = typeof item.id === "string" ? item.id : "";
|
|
50351
|
+
const mapped = remapped.get(origId);
|
|
50352
|
+
if (mapped) {
|
|
50353
|
+
remapped.delete(origId);
|
|
50354
|
+
yield { kind: "meta", chunk: rewriteItemEvent(type, obj, mapped), firstRoundOnly: false };
|
|
50355
|
+
} else if (!suppressTextLifecycle) {
|
|
50356
|
+
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
50357
|
+
}
|
|
50299
50358
|
} else if (item?.type !== "message" || !suppressTextLifecycle) {
|
|
50300
50359
|
yield { kind: "meta", chunk: rawBuf, firstRoundOnly: true };
|
|
50301
50360
|
}
|
|
@@ -53623,15 +53682,15 @@ ${bodyBuffer.toString("utf8")}`);
|
|
|
53623
53682
|
const model = parsed.model;
|
|
53624
53683
|
if (model) {
|
|
53625
53684
|
const embeddedUrl = route?.rewrittenUrl;
|
|
53626
|
-
|
|
53627
|
-
|
|
53628
|
-
|
|
53629
|
-
|
|
53630
|
-
|
|
53631
|
-
|
|
53632
|
-
|
|
53633
|
-
|
|
53634
|
-
|
|
53685
|
+
const host = (() => {
|
|
53686
|
+
try {
|
|
53687
|
+
return embeddedUrl ? new URL(embeddedUrl).host : void 0;
|
|
53688
|
+
} catch {
|
|
53689
|
+
return void 0;
|
|
53690
|
+
}
|
|
53691
|
+
})();
|
|
53692
|
+
let native = pluginReportedContextWindow(req.headers) ?? (host ? peekRegistryContext(model, host) : void 0) ?? resolveContextLimit(opts.routes, embeddedUrl, model);
|
|
53693
|
+
if (!native && host) {
|
|
53635
53694
|
native = await contextFromRegistry(model, host);
|
|
53636
53695
|
}
|
|
53637
53696
|
reqConfig = resolveRequestConfig(config, opts.routes, embeddedUrl, model, native, opts.compress);
|
|
@@ -58402,14 +58461,6 @@ var HEALTH_POLL_INTERVAL_MS = 200;
|
|
|
58402
58461
|
var SPAWN_WAIT_MS = 2e4;
|
|
58403
58462
|
var PROBE_TIMEOUT_MS = 1500;
|
|
58404
58463
|
var DEFAULT_MITM_DOMAIN_SET = new Set(DEFAULT_MITM_DOMAINS.map((d) => d.toLowerCase()));
|
|
58405
|
-
function coveredByDefaultMitm(host) {
|
|
58406
|
-
const h = host.toLowerCase();
|
|
58407
|
-
return DEFAULT_MITM_DOMAINS.some((d) => h === d || h.endsWith("." + d));
|
|
58408
|
-
}
|
|
58409
|
-
function domainsNeedFreshProxy(domains) {
|
|
58410
|
-
if (!domains || domains.length === 0) return false;
|
|
58411
|
-
return domains.some((d) => !coveredByDefaultMitm(d));
|
|
58412
|
-
}
|
|
58413
58464
|
function isLaunchClient(value) {
|
|
58414
58465
|
return LAUNCH_CLIENTS.includes(value);
|
|
58415
58466
|
}
|
|
@@ -58783,10 +58834,6 @@ async function ensureProxyRunning(opts, deps = {}) {
|
|
|
58783
58834
|
const spawnImpl = deps.spawnImpl ?? spawn;
|
|
58784
58835
|
const now = deps.now ?? Date.now;
|
|
58785
58836
|
const sleepImpl = deps.sleep ?? ((ms2) => new Promise((r) => setTimeout(r, ms2)));
|
|
58786
|
-
const preferredOrigin = proxyOrigin(opts.host, opts.port);
|
|
58787
|
-
if (!domainsNeedFreshProxy(opts.mitmDomains) && await probeHealth(preferredOrigin, fetchImpl)) {
|
|
58788
|
-
return { origin: preferredOrigin, port: opts.port, reused: true, child: null };
|
|
58789
|
-
}
|
|
58790
58837
|
const port = await findFreePort(opts.port, opts.host);
|
|
58791
58838
|
const spawnedOrigin = proxyOrigin(opts.host, port);
|
|
58792
58839
|
const script = process.argv[1];
|
|
@@ -58821,7 +58868,7 @@ async function ensureProxyRunning(opts, deps = {}) {
|
|
|
58821
58868
|
while (now() < deadline) {
|
|
58822
58869
|
await sleepImpl(HEALTH_POLL_INTERVAL_MS);
|
|
58823
58870
|
if (await probeHealth(spawnedOrigin, fetchImpl)) {
|
|
58824
|
-
return { origin: spawnedOrigin, port,
|
|
58871
|
+
return { origin: spawnedOrigin, port, child, logPath: logPath2 };
|
|
58825
58872
|
}
|
|
58826
58873
|
}
|
|
58827
58874
|
throw new Error(`bili: proxy did not become healthy at ${spawnedOrigin} within ${SPAWN_WAIT_MS}ms`);
|
|
@@ -58907,7 +58954,7 @@ async function runLaunch(params, deps = {}) {
|
|
|
58907
58954
|
const domains = dedupeInOrder([...routes.httpsDomains, ...params.mitmDomains ?? []]);
|
|
58908
58955
|
const handle2 = await ensureProxyRunning({ host, port, passthrough, debug, mitmDomains: domains }, deps);
|
|
58909
58956
|
console.error(
|
|
58910
|
-
`bili:
|
|
58957
|
+
`bili: started proxy at ${handle2.origin} (MITM domains: ${domains.length ? domains.join(", ") : "defaults"})` + (routes.httpRewrites.length > 0 ? ` (HTTP /bili/ rewrites: ${routes.httpRewrites.length})` : "") + (routes.httpsRewrites.length > 0 ? ` (HTTPS cert rewrites: ${routes.httpsRewrites.length})` : "") + (params.client === "pi-test" ? " (no extensions)" : "")
|
|
58911
58958
|
);
|
|
58912
58959
|
if (handle2.logPath) {
|
|
58913
58960
|
console.error(`bili: proxy log: ${handle2.logPath}`);
|
|
@@ -58981,7 +59028,7 @@ async function runLaunch(params, deps = {}) {
|
|
|
58981
59028
|
console.error(`bili: failed to launch ${params.client}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
58982
59029
|
code = 1;
|
|
58983
59030
|
} finally {
|
|
58984
|
-
|
|
59031
|
+
stopProxy(handle2);
|
|
58985
59032
|
if (piTmpHome) {
|
|
58986
59033
|
try {
|
|
58987
59034
|
fs10.rmSync(piTmpHome, { recursive: true, force: true });
|
|
@@ -59021,7 +59068,7 @@ async function runTestPi(params, deps = {}) {
|
|
|
59021
59068
|
]);
|
|
59022
59069
|
const handle2 = await ensureProxyRunning({ host, port, passthrough, debug, mitmDomains: domains }, deps);
|
|
59023
59070
|
console.error(
|
|
59024
|
-
`bili:
|
|
59071
|
+
`bili: started proxy at ${handle2.origin} (MITM domains: ${domains.length ? domains.join(", ") : "defaults"})`
|
|
59025
59072
|
);
|
|
59026
59073
|
if (handle2.logPath) {
|
|
59027
59074
|
console.error(`bili: proxy log: ${handle2.logPath}`);
|
|
@@ -59050,7 +59097,7 @@ async function runTestPi(params, deps = {}) {
|
|
|
59050
59097
|
console.error(`bili: pi test failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
59051
59098
|
code = 1;
|
|
59052
59099
|
} finally {
|
|
59053
|
-
|
|
59100
|
+
stopProxy(handle2);
|
|
59054
59101
|
}
|
|
59055
59102
|
process.exit(code ?? 0);
|
|
59056
59103
|
}
|
|
@@ -59243,8 +59290,7 @@ Usage:
|
|
|
59243
59290
|
bili --help show this help
|
|
59244
59291
|
|
|
59245
59292
|
Launcher (bili pi / bili codex / bili claude / bili omp / bili opencode):
|
|
59246
|
-
Brings up a proxy on an independent port (
|
|
59247
|
-
that port), then runs the client pointed at it via HTTPS_PROXY + the proxy's
|
|
59293
|
+
Brings up a proxy on an independent port (a fresh instance every launch), then runs the client pointed at it via HTTPS_PROXY + the proxy's
|
|
59248
59294
|
MITM CA \u2014 no config-file edits. Discovered HTTPS upstream domains are
|
|
59249
59295
|
auto-whitelisted for MITM so the proxy TLS-terminates exactly the hosts the
|
|
59250
59296
|
client uses; HTTP / localhost providers go direct. pi/claude trust the CA
|