138 lines
5.1 KiB
TypeScript
138 lines
5.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawn } from "node:child_process";
|
|
import { createServer } from "node:http";
|
|
import test from "node:test";
|
|
|
|
const bunCommand = process.env.HWLAB_TEST_BUN_COMMAND || process.env.HWLAB_BUN_COMMAND || (process.versions.bun ? process.execPath : "bun");
|
|
|
|
const zstdPayload = Buffer.from([
|
|
0x28, 0xb5, 0x2f, 0xfd, 0x04, 0x58, 0x75, 0x03, 0x00, 0x32, 0x47, 0x16,
|
|
0x18, 0xa0, 0xa7, 0x39, 0x64, 0x06, 0x2d, 0xdf, 0x85, 0x36, 0x31, 0xd8,
|
|
0xd4, 0x6c, 0x92, 0xb2, 0x4d, 0x00, 0x06, 0xdd, 0x98, 0xe9, 0x7f, 0x11,
|
|
0x02, 0x4d, 0xd0, 0x9a, 0x4d, 0x59, 0xd4, 0xe1, 0x48, 0x55, 0x64, 0x87,
|
|
0x85, 0xa7, 0x17, 0xc3, 0x0b, 0x44, 0x87, 0x34, 0x67, 0xde, 0x2c, 0x9f,
|
|
0x8f, 0x30, 0x99, 0x38, 0xa9, 0xb3, 0x25, 0x19, 0x03, 0x9f, 0xaf, 0xc7,
|
|
0x9a, 0x05, 0xce, 0x2b, 0x95, 0x5a, 0x13, 0xab, 0xcc, 0x1b, 0x9f, 0xd7,
|
|
0xd0, 0x74, 0x4c, 0xbc, 0x68, 0x0a, 0x80, 0xf0, 0x2f, 0xfd, 0x09, 0x9f,
|
|
0xf3, 0x84, 0x42, 0x66, 0x01, 0x06, 0x00, 0x4e, 0x20, 0xe8, 0x2a, 0x21,
|
|
0x04, 0x03, 0x3f, 0x0d, 0x38, 0x75, 0xb3, 0x32, 0x85, 0x32, 0x03, 0xdb,
|
|
0x5b, 0xed, 0x15
|
|
]);
|
|
|
|
test("DeepSeek Responses bridge decompresses Codex zstd body and maps models catalog", async () => {
|
|
const upstream = await startUpstream();
|
|
const bridge = await startBridge(upstream.port);
|
|
try {
|
|
const response = await fetch(`http://127.0.0.1:${bridge.port}/v1/responses`, {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
"content-encoding": "zstd"
|
|
},
|
|
body: zstdPayload
|
|
});
|
|
assert.equal(response.status, 200);
|
|
assert.equal(upstream.captured.url, "/v1/responses");
|
|
assert.equal(upstream.captured.encoding, null);
|
|
const forwarded = JSON.parse(upstream.captured.body);
|
|
assert.equal(forwarded.model, "deepseek-chat");
|
|
assert.deepEqual(forwarded.tools.map((tool) => tool.type), ["function", "function"]);
|
|
|
|
const readinessResponse = await fetch(`http://127.0.0.1:${bridge.port}/health/readiness`);
|
|
assert.equal(readinessResponse.status, 200);
|
|
const readiness = await readinessResponse.json();
|
|
assert.equal(readiness.upstream.source, "/v1/models");
|
|
assert.equal(readiness.upstream.payload.modelCount, 1);
|
|
|
|
const modelsResponse = await fetch(`http://127.0.0.1:${bridge.port}/v1/models?client_version=test`);
|
|
assert.equal(modelsResponse.status, 200);
|
|
const models = await modelsResponse.json();
|
|
assert.equal(Array.isArray(models.models), true);
|
|
assert.equal(models.models[0].slug, "deepseek-chat");
|
|
} finally {
|
|
await bridge.stop();
|
|
await upstream.stop();
|
|
}
|
|
});
|
|
|
|
async function startUpstream() {
|
|
let captured = null;
|
|
const server = createServer(async (request, response) => {
|
|
if ((request.url || "").startsWith("/health/readiness")) {
|
|
response.writeHead(404, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ error: "not implemented" }));
|
|
return;
|
|
}
|
|
if ((request.url || "").startsWith("/v1/models")) {
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ data: [{ id: "deepseek-chat" }] }));
|
|
return;
|
|
}
|
|
const chunks = [];
|
|
for await (const chunk of request) chunks.push(chunk);
|
|
captured = {
|
|
url: request.url,
|
|
method: request.method,
|
|
encoding: request.headers["content-encoding"] || null,
|
|
length: request.headers["content-length"] || null,
|
|
body: Buffer.concat(chunks).toString("utf8")
|
|
};
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ ok: true }));
|
|
});
|
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
return {
|
|
port: server.address().port,
|
|
get captured() {
|
|
return captured;
|
|
},
|
|
stop: () => new Promise((resolve) => server.close(resolve))
|
|
};
|
|
}
|
|
|
|
async function startBridge(upstreamPort) {
|
|
const port = await freePort();
|
|
const child = spawn(bunCommand, ["run", "cmd/hwlab-deepseek-responses-bridge/main.ts"], {
|
|
cwd: process.cwd(),
|
|
env: {
|
|
...process.env,
|
|
PORT: String(port),
|
|
HWLAB_DEEPSEEK_BRIDGE_UPSTREAM: `http://127.0.0.1:${upstreamPort}`,
|
|
HWLAB_DEEPSEEK_BRIDGE_MODEL: "deepseek-chat"
|
|
},
|
|
stdio: ["ignore", "pipe", "pipe"]
|
|
});
|
|
let stderr = "";
|
|
child.stderr.on("data", (chunk) => {
|
|
stderr += chunk;
|
|
});
|
|
await new Promise((resolve, reject) => {
|
|
const timer = setTimeout(() => reject(new Error(`bridge did not start: ${stderr}`)), 5000);
|
|
child.stdout.on("data", (chunk) => {
|
|
if (chunk.toString().includes("listening")) {
|
|
clearTimeout(timer);
|
|
resolve();
|
|
}
|
|
});
|
|
child.on("exit", (code) => {
|
|
clearTimeout(timer);
|
|
reject(new Error(`bridge exited early code=${code}: ${stderr}`));
|
|
});
|
|
});
|
|
return {
|
|
port,
|
|
stop: async () => {
|
|
child.kill("SIGTERM");
|
|
await new Promise((resolve) => child.once("exit", resolve));
|
|
}
|
|
};
|
|
}
|
|
|
|
async function freePort() {
|
|
const server = createServer();
|
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const port = server.address().port;
|
|
await new Promise((resolve) => server.close(resolve));
|
|
return port;
|
|
}
|