chore: import upstream snapshot with attribution
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:03:20 +08:00
commit 0ef5fcb1c5
1951 changed files with 606278 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
// Dedicated entry for OpenCode's plugin loader.
//
// OpenCode loads a plugin module and treats its exports as plugin factories —
// it rejects the module if a non-function export is present ("Plugin export is
// not a function"). The library barrel (index.ts) re-exports helpers/constants,
// so it cannot be loaded directly. This entry exports ONLY the plugin function.
export { HeadroomPlugin as default } from "./plugin.js";
+23
View File
@@ -0,0 +1,23 @@
export {
DEFAULT_MODEL,
DEFAULT_MODELS,
buildOpencodeConfigContent,
buildOpencodeConfigContentJson,
createHeadroomProvider,
} from "./provider.js";
export type {
HeadroomModelMapping,
HeadroomProvider,
HeadroomProviderOptions,
} from "./provider.js";
export {
compressWithHeadroom,
createHeadroomRetrieveTool,
getDefaultProxyUrl,
setDefaultProxyUrl,
} from "./retrieve.js";
export type { RetrieveToolConfig } from "./retrieve.js";
export { HeadroomPlugin, default } from "./plugin.js";
export type { HeadroomOpenCodePluginOptions } from "./plugin.js";
export { installHeadroomTransport } from "./transport.js";
+68
View File
@@ -0,0 +1,68 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { HeadroomPlugin } from "./plugin.js";
function pluginInput() {
return {
client: {},
project: { id: "project-1" },
directory: "/repo",
worktree: "/repo",
experimental_workspace: {
register: vi.fn(),
},
$: {},
} as never;
}
afterEach(() => {
vi.restoreAllMocks();
});
describe("HeadroomPlugin", () => {
it("adds only Headroom metadata to shell env", async () => {
const plugin = await HeadroomPlugin(pluginInput(), {
proxyUrl: "http://127.0.0.1:8787/",
backend: "litellm",
});
const output = {
env: {
OPENAI_BASE_URL: "https://deepseek.example/v1",
ANTHROPIC_BASE_URL: "https://anthropic.example",
},
};
await plugin["shell.env"]?.({ cwd: "/repo" }, output);
expect(output.env).toMatchObject({
HEADROOM_ACTIVE: "1",
HEADROOM_PROXY_URL: "http://127.0.0.1:8787",
HEADROOM_PROJECT: "project-1",
HEADROOM_BACKEND: "litellm",
OPENAI_BASE_URL: "https://deepseek.example/v1",
ANTHROPIC_BASE_URL: "https://anthropic.example",
});
});
it("exposes a headroom_retrieve tool backed by the proxy", async () => {
const fetchMock = vi.fn(async () => ({
ok: true,
json: async () => "original content",
}));
vi.stubGlobal("fetch", fetchMock);
const plugin = await HeadroomPlugin(pluginInput(), {
proxyUrl: "http://127.0.0.1:8787",
});
const result = await plugin.tool?.headroom_retrieve.execute(
{ hash: "0123456789abcdef01234567" },
{} as never,
);
expect(result).toBe("original content");
expect(fetchMock).toHaveBeenCalledWith(
"http://127.0.0.1:8787/v1/retrieve/0123456789abcdef01234567",
expect.any(Object),
);
});
});
+68
View File
@@ -0,0 +1,68 @@
import type { Plugin } from "@opencode-ai/plugin";
import { tool } from "@opencode-ai/plugin";
import { z } from "zod";
import { createHeadroomRetrieveTool, getDefaultProxyUrl } from "./retrieve.js";
import { installHeadroomTransport } from "./transport.js";
export interface HeadroomOpenCodePluginOptions {
proxyUrl?: string;
project?: string;
backend?: string;
debug?: boolean;
}
function normalizeProxyUrl(url: string): string {
return url.replace(/\/+$/, "");
}
function resolveProxyUrl(options?: HeadroomOpenCodePluginOptions): string {
return normalizeProxyUrl(
options?.proxyUrl ??
process.env.HEADROOM_PROXY_URL ??
process.env.HEADROOM_BASE_URL ??
getDefaultProxyUrl(),
);
}
export const HeadroomPlugin: Plugin = async (input, options = {}) => {
const pluginOptions = options as HeadroomOpenCodePluginOptions;
const proxyUrl = resolveProxyUrl(pluginOptions);
const retrieveTool = createHeadroomRetrieveTool({ proxyBaseUrl: proxyUrl });
const uninstallTransport = installHeadroomTransport({
proxyUrl,
debug: pluginOptions.debug,
});
return {
dispose: async () => {
uninstallTransport();
},
tool: {
headroom_retrieve: tool({
description: retrieveTool.description,
args: {
hash: z
.string()
.regex(/^[a-f0-9]{24}$/i, "Expected 24-character hex hash"),
},
async execute(args) {
return retrieveTool.execute(args);
},
}),
},
"shell.env": async (_input, output) => {
output.env.HEADROOM_ACTIVE = "1";
output.env.HEADROOM_PROXY_URL = proxyUrl;
output.env.HEADROOM_PROJECT =
pluginOptions.project ??
(input.project as { id?: string }).id ??
input.directory;
if (pluginOptions.backend) {
output.env.HEADROOM_BACKEND = pluginOptions.backend;
}
},
};
};
export default HeadroomPlugin;
+89
View File
@@ -0,0 +1,89 @@
export interface HeadroomModelMapping {
name: string;
limit: {
context: number;
output: number;
};
}
export interface HeadroomProviderOptions {
proxyBaseUrl?: string;
proxyPort?: number;
defaultModel?: string;
models?: Record<string, HeadroomModelMapping>;
}
export const DEFAULT_MODELS: Record<string, HeadroomModelMapping> = {
"claude-sonnet-4-6": {
name: "Claude Sonnet 4.6",
limit: { context: 200000, output: 16384 },
},
"claude-opus-4-6": {
name: "Claude Opus 4.6",
limit: { context: 200000, output: 16384 },
},
"claude-haiku-4-5-20251001": {
name: "Claude Haiku 4.5",
limit: { context: 200000, output: 8192 },
},
"gpt-4o": {
name: "GPT-4o",
limit: { context: 128000, output: 16384 },
},
"gpt-4.1": {
name: "GPT-4.1",
limit: { context: 1048576, output: 32768 },
},
};
export const DEFAULT_MODEL = "claude-sonnet-4-6";
function resolveBaseUrl(options: HeadroomProviderOptions): string {
if (options.proxyBaseUrl) return options.proxyBaseUrl.replace(/\/+$/, "");
const port = options.proxyPort ?? 8787;
return `http://127.0.0.1:${port}`;
}
export interface HeadroomProvider {
npm: string;
name: string;
options: {
baseURL: string;
apiKey?: string;
};
models: Record<string, HeadroomModelMapping>;
}
export function createHeadroomProvider(
options: HeadroomProviderOptions = {},
): HeadroomProvider {
const baseUrl = resolveBaseUrl(options);
const models = options.models ?? DEFAULT_MODELS;
return {
npm: "@ai-sdk/openai-compatible",
name: "Headroom Proxy",
options: { baseURL: `${baseUrl}/v1` },
// OpenCode namespaces model ids by provider key, so entries must be bare
// ids ("claude-sonnet-4-6"), referenced as "headroom/<id>".
models: { ...models },
};
}
export function buildOpencodeConfigContent(
options: HeadroomProviderOptions = {},
): Record<string, unknown> {
const defaultModel = options.defaultModel ?? DEFAULT_MODEL;
const provider = createHeadroomProvider(options);
return {
provider: { headroom: provider },
model: `headroom/${defaultModel}`,
};
}
export function buildOpencodeConfigContentJson(
options: HeadroomProviderOptions = {},
): string {
return JSON.stringify(buildOpencodeConfigContent(options));
}
+88
View File
@@ -0,0 +1,88 @@
import type { CompressResult } from "headroom-ai";
import { compress } from "headroom-ai";
let _proxyUrlCache: string | null = null;
export function setDefaultProxyUrl(url: string): void {
_proxyUrlCache = url;
}
export function getDefaultProxyUrl(): string {
return _proxyUrlCache ?? process.env.HEADROOM_BASE_URL ?? "http://localhost:8787";
}
export interface RetrieveToolConfig {
proxyBaseUrl: string;
}
export function createHeadroomRetrieveTool(config: RetrieveToolConfig) {
const origin = config.proxyBaseUrl.replace(/\/+$/, "");
return {
name: "headroom_retrieve",
description:
"Retrieve original uncompressed content from Headroom's compression store. " +
"Use when compressed context mentions a hash and you need the full details. " +
"Pass the hash from the compression marker (24 hex characters). " +
"Retrieval is by hash and always returns the full original content.",
parameters: {
type: "object" as const,
properties: {
hash: {
type: "string",
description: "The 24-character hex hash from the compression marker",
},
},
required: ["hash"],
},
execute: async (args: { hash: string }): Promise<string> => {
const { hash } = args;
if (!/^[a-f0-9]{24}$/i.test(hash)) {
return JSON.stringify({
error: "Invalid hash format. Expected 24 hex characters.",
});
}
try {
const url = `${origin}/v1/retrieve/${hash}`;
const resp = await fetch(url, {
signal: AbortSignal.timeout(10_000),
});
if (!resp.ok) {
const body = await resp.text().catch(() => "");
return JSON.stringify({
error: `Retrieval failed: HTTP ${resp.status}`,
details: body,
});
}
const data = await resp.json();
return typeof data === "string" ? data : JSON.stringify(data);
} catch (error) {
return JSON.stringify({
error: `Retrieval failed: ${error}`,
hint: "The compressed content may have expired (default TTL: 5 minutes)",
});
}
},
};
}
export async function compressWithHeadroom(
messages: unknown[],
options: {
model?: string;
tokenBudget?: number;
proxyUrl?: string;
} = {},
): Promise<CompressResult> {
return compress(messages, {
baseUrl: options.proxyUrl ?? getDefaultProxyUrl(),
model: options.model ?? "gpt-4o",
tokenBudget: options.tokenBudget,
stack: "opencode",
});
}
+379
View File
@@ -0,0 +1,379 @@
import childProcess from "node:child_process";
import http from "node:http";
import http2 from "node:http2";
import https from "node:https";
import { afterEach, describe, expect, it, vi } from "vitest";
import { installHeadroomTransport, uninstallHeadroomTransport } from "./transport.js";
afterEach(() => {
uninstallHeadroomTransport();
vi.restoreAllMocks();
});
type FetchCall = [RequestInfo | URL, RequestInit?];
type SeenRequest = {
method: string | undefined;
url: string | undefined;
headers: http.IncomingHttpHeaders;
body: string;
};
function proxyServer(pathPrefix: string = "/v1"): Promise<{
url: string;
seen: SeenRequest[];
close: () => Promise<void>;
}> {
const seen: SeenRequest[] = [];
const server = http.createServer((req, res) => {
let body = "";
req.setEncoding("utf8");
req.on("data", (chunk) => {
body += chunk;
});
req.on("end", () => {
seen.push({ method: req.method, url: req.url, headers: req.headers, body });
res.writeHead(200, { "content-type": "application/json" });
res.end("{\"ok\":true}");
});
});
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const address = server.address();
if (!address || typeof address === "string") {
reject(new Error("Expected TCP server address"));
return;
}
resolve({
url: `http://127.0.0.1:${address.port}${pathPrefix}`,
seen,
close: () => new Promise((done) => server.close(() => done())),
});
});
});
}
describe("Headroom OpenCode transport", () => {
it("routes fetch chat paths through /v1/chat/completions with proxy base and normalized-path header", async () => {
const proxyTargets = ["http://127.0.0.1:8787", "http://127.0.0.1:8787/v1"];
const upstreamPath = "/api/coding/paas/v4/chat/completions";
for (const proxyUrl of proxyTargets) {
const proxyOrigin = new URL(proxyUrl).origin;
const originalFetch = globalThis.fetch;
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
globalThis.fetch = fetchMock as unknown as typeof fetch;
installHeadroomTransport({ proxyUrl });
await fetch(`https://open.bigmodel.cn${upstreamPath}`, { method: "POST", headers: { "content-type": "application/json" } });
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock.mock.calls[0][0]).toEqual(new URL(`${proxyOrigin}/v1/chat/completions`));
const headers = new Headers(fetchMock.mock.calls[0][1]?.headers);
expect(headers.get("x-headroom-base-url")).toBe("https://open.bigmodel.cn");
expect(headers.get("x-headroom-original-path")).toBe(upstreamPath);
globalThis.fetch = originalFetch;
uninstallHeadroomTransport();
}
});
it("routes fetch responses paths through /v1/responses with proxy base and normalized-path header", async () => {
const proxyTargets = ["http://127.0.0.1:8787", "http://127.0.0.1:8787/v1"];
const upstreamPath = "/api/coding/paas/v4/responses";
for (const proxyUrl of proxyTargets) {
const proxyOrigin = new URL(proxyUrl).origin;
const originalFetch = globalThis.fetch;
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
globalThis.fetch = fetchMock as unknown as typeof fetch;
installHeadroomTransport({ proxyUrl });
await fetch(`https://open.bigmodel.cn${upstreamPath}`, { method: "POST", headers: { "content-type": "application/json" } });
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock.mock.calls[0][0]).toEqual(new URL(`${proxyOrigin}/v1/responses`));
const headers = new Headers(fetchMock.mock.calls[0][1]?.headers);
expect(headers.get("x-headroom-base-url")).toBe("https://open.bigmodel.cn");
expect(headers.get("x-headroom-original-path")).toBe(upstreamPath);
globalThis.fetch = originalFetch;
uninstallHeadroomTransport();
}
});
it("routes external fetch calls through the proxy without pre-registering providers", async () => {
const originalFetch = globalThis.fetch;
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
globalThis.fetch = fetchMock as unknown as typeof fetch;
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
await fetch("https://api.deepseek.com/v1/chat/completions?x=1", {
method: "POST",
headers: { authorization: "Bearer test" },
});
await fetch("https://new-provider.example/base/v1/messages", { method: "POST" });
expect(fetchMock).toHaveBeenNthCalledWith(
1,
new URL("http://127.0.0.1:8787/v1/chat/completions?x=1"),
expect.objectContaining({ method: "POST" }),
);
expect(new Headers(fetchMock.mock.calls[0][1]?.headers).get("x-headroom-base-url")).toBe(
"https://api.deepseek.com",
);
expect(fetchMock.mock.calls[1][0]).toEqual(new URL("http://127.0.0.1:8787/base/v1/messages"));
expect(new Headers(fetchMock.mock.calls[1][1]?.headers).get("x-headroom-base-url")).toBe(
"https://new-provider.example",
);
globalThis.fetch = originalFetch;
});
it("preserves non-prefix paths like /base/v1/messages", async () => {
const originalFetch = globalThis.fetch;
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
globalThis.fetch = fetchMock as unknown as typeof fetch;
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
await fetch("https://example.test/base/v1/messages", { method: "POST" });
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock.mock.calls[0][0]).toEqual(new URL("http://127.0.0.1:8787/base/v1/messages"));
expect(new Headers(fetchMock.mock.calls[0][1]?.headers).get("x-headroom-original-path")).toBeNull();
globalThis.fetch = originalFetch;
});
it("bypasses local, OpenCode, and Headroom proxy fetch URLs", async () => {
const originalFetch = globalThis.fetch;
const fetchMock = vi.fn(async (..._args: FetchCall) => new Response("ok"));
globalThis.fetch = fetchMock as unknown as typeof fetch;
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
await fetch("http://127.0.0.1:8787/v1/retrieve");
await fetch("http://localhost:4096/config");
expect(fetchMock.mock.calls[0][0]).toBe("http://127.0.0.1:8787/v1/retrieve");
expect(fetchMock.mock.calls[1][0]).toBe("http://localhost:4096/config");
globalThis.fetch = originalFetch;
});
it("routes external https.request calls through the proxy", async () => {
const proxy = await proxyServer();
installHeadroomTransport({ proxyUrl: proxy.url });
await new Promise<void>((resolve, reject) => {
const req = https.request(
"https://api.anthropic.com/v1/messages?beta=1",
{ method: "POST", headers: { authorization: "Bearer test" } },
(res) => {
res.resume();
res.on("end", resolve);
},
);
req.on("error", reject);
req.end("{\"model\":\"claude\"}");
});
expect(proxy.seen).toHaveLength(1);
expect(proxy.seen[0]).toMatchObject({ method: "POST", url: "/v1/messages?beta=1" });
expect(proxy.seen[0].headers["x-headroom-base-url"]).toBe("https://api.anthropic.com");
expect(proxy.seen[0].headers.host).toMatch(/^127\.0\.0\.1:/);
expect(proxy.seen[0].body).toBe("{\"model\":\"claude\"}");
await proxy.close();
});
it("normalizes Node HTTP(S) requests for /chat/completions and /responses", async () => {
const proxy = await proxyServer("");
installHeadroomTransport({ proxyUrl: proxy.url });
const httpChatPath = "/api/coding/paas/v4/chat/completions";
const httpResponsesPath = "/api/coding/paas/v4/responses";
const httpsChatPath = "/v4/openai/chat/completions";
const httpsResponsesPath = "/v4/openai/responses";
await new Promise<void>((resolve, reject) => {
const req = http.request(
`http://open.bigmodel.cn${httpChatPath}`,
{ method: "POST", headers: { authorization: "Bearer test" } },
(res) => {
res.resume();
res.on("end", resolve);
},
);
req.on("error", reject);
req.end("{\"model\":\"gpt-4\"}");
});
await new Promise<void>((resolve, reject) => {
const req = http.request(
`http://open.bigmodel.cn${httpResponsesPath}`,
{ method: "POST", headers: { authorization: "Bearer test" } },
(res) => {
res.resume();
res.on("end", resolve);
},
);
req.on("error", reject);
req.end("{\"model\":\"gpt-4\"}");
});
await new Promise<void>((resolve, reject) => {
const req = https.request(
`https://api.deepseek.com${httpsChatPath}`,
{ method: "POST", headers: { authorization: "Bearer test" } },
(res) => {
res.resume();
res.on("end", resolve);
},
);
req.on("error", reject);
req.end("{\"model\":\"gpt-4\"}");
});
await new Promise<void>((resolve, reject) => {
const req = https.request(
`https://api.deepseek.com${httpsResponsesPath}`,
{ method: "POST", headers: { authorization: "Bearer test" } },
(res) => {
res.resume();
res.on("end", resolve);
},
);
req.on("error", reject);
req.end("{\"model\":\"gpt-4\"}");
});
expect(proxy.seen[0]).toMatchObject({
method: "POST",
url: "/v1/chat/completions",
headers: expect.objectContaining({
"x-headroom-base-url": "http://open.bigmodel.cn",
"x-headroom-original-path": httpChatPath,
}),
});
expect(proxy.seen[1]).toMatchObject({
method: "POST",
url: "/v1/responses",
headers: expect.objectContaining({
"x-headroom-base-url": "http://open.bigmodel.cn",
"x-headroom-original-path": httpResponsesPath,
}),
});
expect(proxy.seen[2]).toMatchObject({
method: "POST",
url: "/v1/chat/completions",
headers: expect.objectContaining({
"x-headroom-base-url": "https://api.deepseek.com",
"x-headroom-original-path": httpsChatPath,
}),
});
expect(proxy.seen[3]).toMatchObject({
method: "POST",
url: "/v1/responses",
headers: expect.objectContaining({
"x-headroom-base-url": "https://api.deepseek.com",
"x-headroom-original-path": httpsResponsesPath,
}),
});
await proxy.close();
});
it("blocks external http2 connections instead of leaking them", () => {
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
expect(() => http2.connect("https://api.openai.com")).toThrow(
/blocked direct HTTP\/2 connection to https:\/\/api\.openai\.com/,
);
});
it("preloads the Headroom shim into child Node processes", () => {
const originalNodeOptions = process.env.NODE_OPTIONS;
const originalProxyUrl = process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL;
try {
process.env.NODE_OPTIONS = "--trace-warnings";
delete process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL;
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
expect(process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL).toBe("http://127.0.0.1:8787/v1");
expect(process.env.NODE_OPTIONS).toContain("--trace-warnings");
expect(process.env.NODE_OPTIONS).toContain("--import=file:");
expect(process.env.NODE_OPTIONS).toContain("/hook-shim/handler.js");
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
expect(process.env.NODE_OPTIONS?.match(/hook-shim\/handler\.js/g)).toHaveLength(1);
} finally {
if (originalNodeOptions === undefined) {
delete process.env.NODE_OPTIONS;
} else {
process.env.NODE_OPTIONS = originalNodeOptions;
}
if (originalProxyUrl === undefined) {
delete process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL;
} else {
process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL = originalProxyUrl;
}
uninstallHeadroomTransport();
}
});
it("injects the Headroom shim into child processes with custom env", () => {
const originalSpawn = childProcess.spawn;
const spawnMock = vi.fn(() => ({
on: vi.fn(),
once: vi.fn(),
emit: vi.fn(),
kill: vi.fn(),
killed: false,
pid: 123,
}));
childProcess.spawn = spawnMock as unknown as typeof childProcess.spawn;
try {
installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
childProcess.spawn("node", ["agent.js"], { env: { PATH: "/bin", NODE_OPTIONS: "--trace-warnings" } });
const options = (spawnMock.mock.calls[0] as unknown[])[2] as { env: NodeJS.ProcessEnv };
expect(options.env.PATH).toBe("/bin");
expect(options.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL).toBe("http://127.0.0.1:8787/v1");
expect(options.env.NODE_OPTIONS).toContain("--trace-warnings");
expect(options.env.NODE_OPTIONS).toContain("--import=file:");
expect(options.env.NODE_OPTIONS).toContain("/hook-shim/handler.js");
} finally {
uninstallHeadroomTransport();
childProcess.spawn = originalSpawn;
}
});
it("restores patched transports only after the final disposer", () => {
const originalFetch = globalThis.fetch;
const originalHttpRequest = http.request;
const originalHttpsRequest = https.request;
const firstDispose = installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8787/v1" });
const secondDispose = installHeadroomTransport({ proxyUrl: "http://127.0.0.1:8788/v1" });
expect(globalThis.fetch).not.toBe(originalFetch);
expect(http.request).not.toBe(originalHttpRequest);
expect(https.request).not.toBe(originalHttpsRequest);
firstDispose();
expect(globalThis.fetch).not.toBe(originalFetch);
expect(http.request).not.toBe(originalHttpRequest);
secondDispose();
expect(globalThis.fetch).toBe(originalFetch);
expect(http.request).toBe(originalHttpRequest);
expect(https.request).toBe(originalHttpsRequest);
});
});
+479
View File
@@ -0,0 +1,479 @@
import { createRequire, syncBuiltinESMExports } from "node:module";
const nodeRequire = createRequire(import.meta.url);
const http = nodeRequire("node:http") as typeof import("node:http");
const https = nodeRequire("node:https") as typeof import("node:https");
const http2 = nodeRequire("node:http2") as typeof import("node:http2");
const childProcess = nodeRequire("node:child_process") as typeof import("node:child_process");
const BASE_URL_HEADER = "x-headroom-base-url";
const ORIGINAL_PATH_HEADER = "x-headroom-original-path";
const PROXY_ENV = "HEADROOM_OPENCODE_TRANSPORT_PROXY_URL";
const STATE_KEY = Symbol.for("headroom.opencode.transport");
type FetchArgs = Parameters<typeof fetch>;
type HttpRequest = typeof http.request;
type HttpGet = typeof http.get;
type HttpsRequest = typeof https.request;
type HttpsGet = typeof https.get;
type Http2Connect = typeof http2.connect;
type ChildSpawn = typeof childProcess.spawn;
type ChildExec = typeof childProcess.exec;
type ChildExecFile = typeof childProcess.execFile;
type ChildFork = typeof childProcess.fork;
interface InstallOptions {
proxyUrl: string;
debug?: boolean;
}
interface TransportState {
refs: number;
proxyUrl: string;
debug: boolean;
originalFetch: typeof fetch;
originalHttpRequest: HttpRequest;
originalHttpGet: HttpGet;
originalHttpsRequest: HttpsRequest;
originalHttpsGet: HttpsGet;
originalHttp2Connect: Http2Connect;
originalChildSpawn: ChildSpawn;
originalChildExec: ChildExec;
originalChildExecFile: ChildExecFile;
originalChildFork: ChildFork;
}
interface GlobalWithHeadroomTransport {
[STATE_KEY]?: TransportState;
}
interface NodeRequestParts {
url?: URL;
options: Record<string, unknown>;
callback?: (...args: unknown[]) => unknown;
}
function getState(): TransportState | undefined {
return (globalThis as GlobalWithHeadroomTransport)[STATE_KEY];
}
function setState(state: TransportState | undefined): void {
(globalThis as GlobalWithHeadroomTransport)[STATE_KEY] = state;
}
function shimImportSpecifier(): string {
return new URL("../hook-shim/handler.js", import.meta.url).href;
}
function withNodeImportOption(existing: string | undefined, shim: string): string {
const parts = existing?.trim() ? existing.trim().split(/\s+/) : [];
const alreadyPresent = parts.some((part, index) => {
return part === `--import=${shim}` || (part === "--import" && parts[index + 1] === shim);
});
if (!alreadyPresent) {
parts.push(`--import=${shim}`);
}
return parts.join(" ");
}
function withShimEnv(env: NodeJS.ProcessEnv | Record<string, unknown> | undefined, proxyUrl: string): NodeJS.ProcessEnv {
const nextEnv = { ...(env ?? process.env) } as NodeJS.ProcessEnv;
nextEnv[PROXY_ENV] = proxyUrl;
nextEnv.NODE_OPTIONS = withNodeImportOption(nextEnv.NODE_OPTIONS, shimImportSpecifier());
return nextEnv;
}
function installProcessEnv(proxyUrl: string): void {
process.env[PROXY_ENV] = proxyUrl;
process.env.NODE_OPTIONS = withNodeImportOption(process.env.NODE_OPTIONS, shimImportSpecifier());
}
function isOptions(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !(value instanceof URL);
}
function injectOptionsEnv(args: unknown[], optionIndex: number, proxyUrl: string): unknown[] {
const nextArgs = [...args];
const callback = typeof nextArgs.at(-1) === "function" ? nextArgs.pop() : undefined;
const existing = isOptions(nextArgs[optionIndex]) ? { ...(nextArgs[optionIndex] as Record<string, unknown>) } : {};
existing.env = withShimEnv(existing.env as NodeJS.ProcessEnv | undefined, proxyUrl);
if (isOptions(nextArgs[optionIndex])) {
nextArgs[optionIndex] = existing;
} else {
nextArgs.splice(optionIndex, 0, existing);
}
if (callback) {
nextArgs.push(callback);
}
return nextArgs;
}
function wrapSpawn(originalSpawn: ChildSpawn): ChildSpawn {
return function headroomSpawn(this: unknown, ...args: unknown[]) {
const state = getState();
if (!state) {
return Reflect.apply(originalSpawn, this, args);
}
const optionIndex = Array.isArray(args[1]) ? 2 : 1;
return Reflect.apply(originalSpawn, this, injectOptionsEnv(args, optionIndex, state.proxyUrl));
} as ChildSpawn;
}
function wrapExec(originalExec: ChildExec): ChildExec {
return function headroomExec(this: unknown, ...args: unknown[]) {
const state = getState();
if (!state) {
return Reflect.apply(originalExec, this, args);
}
return Reflect.apply(originalExec, this, injectOptionsEnv(args, 1, state.proxyUrl));
} as ChildExec;
}
function wrapExecFile(originalExecFile: ChildExecFile): ChildExecFile {
return function headroomExecFile(this: unknown, ...args: unknown[]) {
const state = getState();
if (!state) {
return Reflect.apply(originalExecFile, this, args);
}
const optionIndex = Array.isArray(args[1]) ? 2 : 1;
return Reflect.apply(originalExecFile, this, injectOptionsEnv(args, optionIndex, state.proxyUrl));
} as ChildExecFile;
}
function wrapFork(originalFork: ChildFork): ChildFork {
return function headroomFork(this: unknown, ...args: unknown[]) {
const state = getState();
if (!state) {
return Reflect.apply(originalFork, this, args);
}
const optionIndex = Array.isArray(args[1]) ? 2 : 1;
return Reflect.apply(originalFork, this, injectOptionsEnv(args, optionIndex, state.proxyUrl));
} as ChildFork;
}
function normalizeProxyUrl(proxyUrl: string): URL {
return new URL(proxyUrl);
}
function isLoopback(hostname: string): boolean {
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
}
function shouldRoute(url: URL, proxy: URL): boolean {
if (url.protocol !== "http:" && url.protocol !== "https:") {
return false;
}
if (isLoopback(url.hostname)) {
return false;
}
if (url.origin === proxy.origin) {
return false;
}
return true;
}
function routedUrl(upstream: URL, proxy: URL): URL {
return new URL(`${upstream.pathname}${upstream.search}`, proxy.origin);
}
function normalizedOpenAiProxyPath(pathname: string): string | undefined {
if (pathname.endsWith("/chat/completions")) {
return "/v1/chat/completions";
}
if (pathname.endsWith("/responses")) {
return "/v1/responses";
}
return undefined;
}
function routedUrlForOpenCode(upstream: URL, proxy: URL): { url: URL; originalPath: string | undefined } {
const normalizedPath = normalizedOpenAiProxyPath(upstream.pathname);
if (!normalizedPath) {
return {
url: routedUrl(upstream, proxy),
originalPath: undefined,
};
}
return {
url: new URL(`${normalizedPath}${upstream.search}`, proxy.origin),
originalPath: upstream.pathname,
};
}
function requestUrl(input: RequestInfo | URL): URL {
if (input instanceof Request) {
return new URL(input.url);
}
if (input instanceof URL) {
return input;
}
return new URL(String(input));
}
function mergeFetchHeaders(
input: RequestInfo | URL,
init: RequestInit | undefined,
upstream: URL | undefined,
originalPath: string | undefined = undefined,
): Headers {
const headers = new Headers(input instanceof Request ? input.headers : undefined);
if (init?.headers) {
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
}
if (upstream) {
headers.set(BASE_URL_HEADER, upstream.origin);
headers.delete("host");
}
if (originalPath) {
headers.set(ORIGINAL_PATH_HEADER, originalPath);
}
return headers;
}
function withRoutedFetchInput(input: RequestInfo | URL, init: RequestInit | undefined, proxy: URL): FetchArgs {
const upstream = requestUrl(input);
if (!shouldRoute(upstream, proxy)) {
return [input, init];
}
const { url: nextUrl, originalPath } = routedUrlForOpenCode(upstream, proxy);
const nextInit = {
...init,
headers: mergeFetchHeaders(input, init, upstream, originalPath),
};
if (input instanceof Request) {
return [new Request(nextUrl, input), nextInit];
}
return [nextUrl, nextInit];
}
function splitNodeArgs(args: unknown[]): NodeRequestParts {
const callback = typeof args.at(-1) === "function" ? (args.at(-1) as (...args: unknown[]) => unknown) : undefined;
const withoutCallback = callback ? args.slice(0, -1) : args;
const [first, second] = withoutCallback;
const options = typeof second === "object" && second !== null ? { ...(second as Record<string, unknown>) } : {};
if (first instanceof URL) {
return { url: first, options, callback };
}
if (typeof first === "string") {
try {
return { url: new URL(first), options, callback };
} catch {
return { options, callback };
}
}
if (typeof first === "object" && first !== null) {
const requestOptions = { ...(first as Record<string, unknown>), ...options };
return { url: urlFromRequestOptions(requestOptions), options: requestOptions, callback };
}
return { options, callback };
}
function urlFromRequestOptions(options: Record<string, unknown>): URL | undefined {
const protocol = String(options.protocol ?? "http:");
if (protocol !== "http:" && protocol !== "https:") {
return undefined;
}
const hostValue = options.hostname ?? options.host;
if (!hostValue) {
return undefined;
}
const hostname = String(hostValue).replace(/:\d+$/, "");
const port = options.port ? `:${String(options.port)}` : "";
const path = String(options.path ?? "/");
try {
return new URL(`${protocol}//${hostname}${port}${path}`);
} catch {
return undefined;
}
}
function headersForNodeRequest(
options: Record<string, unknown>,
upstream: URL,
originalPath: string | undefined,
): Record<string, string> {
const headers = new Headers(options.headers as HeadersInit | undefined);
headers.set(BASE_URL_HEADER, upstream.origin);
if (originalPath) {
headers.set(ORIGINAL_PATH_HEADER, originalPath);
}
headers.delete("host");
const result: Record<string, string> = {};
headers.forEach((value, key) => {
result[key] = value;
});
return result;
}
function routedNodeOptions(parts: NodeRequestParts, proxy: URL): Record<string, unknown> | undefined {
if (!parts.url || !shouldRoute(parts.url, proxy)) {
return undefined;
}
const { url: nextUrl, originalPath } = routedUrlForOpenCode(parts.url, proxy);
const {
agent: _agent,
auth: _auth,
createConnection: _createConnection,
defaultPort: _defaultPort,
family: _family,
headers: _headers,
host: _host,
hostname: _hostname,
href: _href,
lookup: _lookup,
path: _path,
pathname: _pathname,
port: _port,
protocol: _protocol,
search: _search,
servername: _servername,
setHost: _setHost,
...rest
} = parts.options;
return {
...rest,
protocol: nextUrl.protocol,
hostname: nextUrl.hostname,
port: nextUrl.port || undefined,
path: `${nextUrl.pathname}${nextUrl.search}`,
headers: headersForNodeRequest(parts.options, parts.url, originalPath),
};
}
function wrapRequest(
originalHttpRequest: HttpRequest,
originalHttpsRequest: HttpsRequest,
originalRequest: HttpRequest | HttpsRequest,
): HttpRequest | HttpsRequest {
return function headroomRequest(this: unknown, ...args: unknown[]) {
const state = getState();
if (!state) {
return Reflect.apply(originalRequest, this, args);
}
const proxy = normalizeProxyUrl(state.proxyUrl);
const parts = splitNodeArgs(args);
const nextOptions = routedNodeOptions(parts, proxy);
if (!nextOptions) {
return Reflect.apply(originalRequest, this, args);
}
const targetRequest = proxy.protocol === "https:" ? originalHttpsRequest : originalHttpRequest;
const nextArgs = parts.callback ? [nextOptions, parts.callback] : [nextOptions];
return Reflect.apply(targetRequest, this, nextArgs);
} as HttpRequest | HttpsRequest;
}
function wrapGet(request: HttpRequest | HttpsRequest): HttpGet | HttpsGet {
return function headroomGet(this: unknown, ...args: unknown[]) {
const req = Reflect.apply(request, this, args);
req.end();
return req;
} as HttpGet | HttpsGet;
}
function wrapHttp2Connect(originalConnect: Http2Connect): Http2Connect {
return function headroomHttp2Connect(this: unknown, authority: string | URL, ...args: unknown[]) {
const state = getState();
if (state) {
const proxy = normalizeProxyUrl(state.proxyUrl);
const upstream = authority instanceof URL ? authority : new URL(String(authority));
if (shouldRoute(upstream, proxy)) {
throw new Error(
`Headroom OpenCode wrap blocked direct HTTP/2 connection to ${upstream.origin}. ` +
"Use fetch, http, or https so traffic can be routed through Headroom.",
);
}
}
return Reflect.apply(originalConnect, this, [authority, ...args]);
} as Http2Connect;
}
export function installHeadroomTransport(options: InstallOptions): () => void {
const existing = getState();
if (existing) {
existing.refs += 1;
existing.proxyUrl = options.proxyUrl;
existing.debug = Boolean(options.debug);
installProcessEnv(options.proxyUrl);
return () => uninstallHeadroomTransport();
}
const state: TransportState = {
refs: 1,
proxyUrl: options.proxyUrl,
debug: Boolean(options.debug),
originalFetch: globalThis.fetch,
originalHttpRequest: http.request,
originalHttpGet: http.get,
originalHttpsRequest: https.request,
originalHttpsGet: https.get,
originalHttp2Connect: http2.connect,
originalChildSpawn: childProcess.spawn,
originalChildExec: childProcess.exec,
originalChildExecFile: childProcess.execFile,
originalChildFork: childProcess.fork,
};
setState(state);
installProcessEnv(options.proxyUrl);
globalThis.fetch = async (...args: FetchArgs) => {
const current = getState();
if (!current) {
return state.originalFetch(...args);
}
const proxy = normalizeProxyUrl(current.proxyUrl);
const [nextInput, nextInit] = withRoutedFetchInput(args[0], args[1], proxy);
return state.originalFetch(nextInput, nextInit);
};
http.request = wrapRequest(state.originalHttpRequest, state.originalHttpsRequest, state.originalHttpRequest) as HttpRequest;
https.request = wrapRequest(state.originalHttpRequest, state.originalHttpsRequest, state.originalHttpsRequest) as HttpsRequest;
http.get = wrapGet(http.request) as HttpGet;
https.get = wrapGet(https.request) as HttpsGet;
http2.connect = wrapHttp2Connect(state.originalHttp2Connect);
childProcess.spawn = wrapSpawn(state.originalChildSpawn);
childProcess.exec = wrapExec(state.originalChildExec);
childProcess.execFile = wrapExecFile(state.originalChildExecFile);
childProcess.fork = wrapFork(state.originalChildFork);
syncBuiltinESMExports();
return () => uninstallHeadroomTransport();
}
export function uninstallHeadroomTransport(): void {
const state = getState();
if (!state) {
return;
}
state.refs -= 1;
if (state.refs > 0) {
return;
}
globalThis.fetch = state.originalFetch;
http.request = state.originalHttpRequest;
http.get = state.originalHttpGet;
https.request = state.originalHttpsRequest;
https.get = state.originalHttpsGet;
http2.connect = state.originalHttp2Connect;
childProcess.spawn = state.originalChildSpawn;
childProcess.exec = state.originalChildExec;
childProcess.execFile = state.originalChildExecFile;
childProcess.fork = state.originalChildFork;
syncBuiltinESMExports();
setState(undefined);
}