codex-flows/packages/codex-opencode-go-router/test/selftest.mjs
matamune 3e0d9e057b
Some checks failed
ci / check (push) Failing after 16s
Add Codex OpenCode Go router package
2026-05-14 03:06:13 +00:00

259 lines
8.3 KiB
JavaScript
Executable file

#!/usr/bin/env node
import { createServer } from "node:http";
import { request as httpRequest } from "node:http";
import { spawn } from "node:child_process";
const adapterPath = new URL("../src/router.mjs", import.meta.url).pathname;
const fakeUpstreamPort = 61981;
const adapterPort = 61982;
const seenRequests = [];
const fakeUpstream = createServer(async (request, response) => {
const body = JSON.parse(await readBody(request));
seenRequests.push(body);
const tool = body.tools?.[0]?.function;
const content = body.messages?.map((message) => message.content).join("\n") ?? "";
if (content.includes("reasoning-followup")) {
const assistant = body.messages.find((message) => message.role === "assistant" && message.tool_calls);
if (assistant?.reasoning_content !== "deepseek-thought") {
sendJson(response, 400, {
error: { message: "missing reasoning_content replay" },
});
return;
}
sendJson(response, 200, completion({ content: "reasoning-ok" }));
return;
}
if (!tool) {
sendJson(response, 200, completion({ content: "plain-ok" }));
return;
}
const args = tool.name.includes("custom")
? JSON.stringify({ input: "custom-input" })
: tool.name.includes("local")
? JSON.stringify({ command: ["echo", "local-ok"] })
: JSON.stringify({ value: "ok" });
sendJson(response, 200, completion({
toolCalls: [{
id: `call_${tool.name}`,
type: "function",
function: { name: tool.name, arguments: args },
}],
reasoningContent: "deepseek-thought",
}));
});
fakeUpstream.listen(fakeUpstreamPort, "127.0.0.1", async () => {
const adapter = spawn(process.execPath, [adapterPath], {
env: {
...process.env,
OPENCODE_GO_API_KEY: "test-key",
OPENCODE_GO_PROXY_HOST: "127.0.0.1",
OPENCODE_GO_PROXY_PORT: String(adapterPort),
OPENCODE_GO_UPSTREAM_URL: `http://127.0.0.1:${fakeUpstreamPort}/chat/completions`,
},
stdio: ["ignore", "pipe", "pipe"],
});
adapter.stderr.on("data", (chunk) => process.stderr.write(chunk));
try {
await waitForHealth(adapterPort);
await assertOutputItem("plain", {
model: "deepseek-v4-pro",
input: "plain",
}, (item) => item.type === "message" && item.content?.[0]?.text === "plain-ok");
await assertOutputItem("function", {
model: "deepseek-v4-pro",
input: "call function",
tools: [{ type: "function", name: "exec_command", parameters: objectSchema() }],
}, (item) => item.type === "function_call" && item.name === "exec_command");
await assertOutputItem("namespace", {
model: "deepseek-v4-pro",
input: "call namespace",
tools: [{
type: "namespace",
name: "mcp__server__",
tools: [{ type: "function", name: "echo", parameters: objectSchema() }],
}],
}, (item) =>
item.type === "function_call" &&
item.namespace === "mcp__server__" &&
item.name === "echo");
await assertOutputItem("custom", {
model: "deepseek-v4-pro",
input: "call custom",
tools: [{ type: "custom", name: "custom_patch" }],
}, (item) =>
item.type === "custom_tool_call" &&
item.name === "custom_patch" &&
item.input === "custom-input");
await assertOutputItem("local_shell", {
model: "deepseek-v4-pro",
input: "call local",
tools: [{ type: "local_shell", name: "local_shell" }],
}, (item) =>
item.type === "local_shell_call" &&
item.action?.command?.join(" ") === "echo local-ok");
await assertOutputItem("tool_search", {
model: "deepseek-v4-pro",
input: "call search",
tools: [{ type: "tool_search", name: "tool_search" }],
}, (item) =>
item.type === "tool_search_call" &&
item.arguments?.value === "ok");
const first = await requestResponses({
model: "deepseek-v4-pro",
input: "reasoning first",
tools: [{ type: "function", name: "exec_command", parameters: objectSchema() }],
});
const call = first.output[0];
await requestResponses({
model: "deepseek-v4-pro",
input: [
call,
{ type: "function_call_output", call_id: call.call_id, output: "done" },
{ type: "message", role: "user", content: [{ type: "input_text", text: "reasoning-followup" }] },
],
});
await requestResponses({
model: "deepseek-v4-pro",
input: [
{ type: "custom_tool_call", call_id: "call_custom_replay", name: "custom_patch", input: "patch" },
{ type: "custom_tool_call_output", call_id: "call_custom_replay", output: "patched" },
{ type: "local_shell_call", call_id: "call_local_replay", status: "completed", action: { type: "exec", command: ["pwd"] } },
{ type: "function_call_output", call_id: "call_local_replay", output: "cwd" },
{ type: "tool_search_call", call_id: "call_search_replay", execution: "client", arguments: { query: "x" } },
{ type: "function_call_output", call_id: "call_search_replay", output: "found" },
{ type: "message", role: "user", content: [{ type: "input_text", text: "plain after replay" }] },
],
});
console.log(JSON.stringify({
ok: true,
cases: [
"plain",
"function",
"namespace",
"custom",
"local_shell",
"tool_search",
"reasoning_replay",
"history_replay",
],
upstreamRequests: seenRequests.length,
}, null, 2));
} finally {
adapter.kill();
fakeUpstream.close();
}
});
function completion({ content = null, toolCalls = undefined, reasoningContent = undefined }) {
return {
id: "chatcmpl_test",
object: "chat.completion",
created: Math.floor(Date.now() / 1000),
model: "deepseek-v4-pro",
choices: [{
index: 0,
message: {
role: "assistant",
content,
...(toolCalls ? { tool_calls: toolCalls } : {}),
...(reasoningContent ? { reasoning_content: reasoningContent } : {}),
},
finish_reason: toolCalls ? "tool_calls" : "stop",
}],
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
};
}
function objectSchema() {
return { type: "object", properties: {} };
}
async function assertOutputItem(label, body, predicate) {
const response = await requestResponses(body);
const item = response.output[0];
if (!predicate(item)) {
throw new Error(`${label} assertion failed: ${JSON.stringify(item)}`);
}
}
async function requestResponses(body) {
const payload = JSON.stringify(body);
const { statusCode, text } = await new Promise((resolve, reject) => {
const req = httpRequest({
hostname: "127.0.0.1",
port: adapterPort,
path: "/v1/responses",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(payload),
},
}, (res) => {
let text = "";
res.setEncoding("utf8");
res.on("data", (chunk) => {
text += chunk;
});
res.on("end", () => resolve({ statusCode: res.statusCode, text }));
});
req.on("error", reject);
req.end(payload);
});
if (statusCode < 200 || statusCode >= 300) {
throw new Error(`adapter returned ${statusCode}: ${text}`);
}
return parseCompletedResponse(text);
}
function parseCompletedResponse(sse) {
for (const chunk of sse.split("\n\n")) {
if (!chunk.includes("event: response.completed")) continue;
const data = chunk.split("\n").find((line) => line.startsWith("data: "))?.slice(6);
return JSON.parse(data).response;
}
throw new Error(`missing response.completed in ${sse}`);
}
async function waitForHealth(port) {
const deadline = Date.now() + 5000;
while (Date.now() < deadline) {
try {
const response = await fetch(`http://127.0.0.1:${port}/health`);
if (response.ok) return;
} catch {}
await new Promise((resolve) => setTimeout(resolve, 50));
}
throw new Error("adapter did not become healthy");
}
function readBody(request) {
return new Promise((resolve, reject) => {
let data = "";
request.setEncoding("utf8");
request.on("data", (chunk) => {
data += chunk;
});
request.on("end", () => resolve(data));
request.on("error", reject);
});
}
function sendJson(response, status, payload) {
response.writeHead(status, { "Content-Type": "application/json" });
response.end(JSON.stringify(payload));
}