81 lines
3.2 KiB
TypeScript
81 lines
3.2 KiB
TypeScript
#!/usr/bin/env bun
|
|
// SPEC: issue-1190 fake Responses provider P1.
|
|
// Responsibility: Local protocol smoke for fake Responses provider without Docker or k3s.
|
|
import { createFakeResponsesProviderService, loadFakeResponsesProviderConfig } from "./src/fake-responses-provider-service";
|
|
|
|
const config = loadFakeResponsesProviderConfig({ ...process.env, LISTEN_HOST: "127.0.0.1" });
|
|
const service = createFakeResponsesProviderService(config);
|
|
const server = Bun.serve({ hostname: "127.0.0.1", port: 0, fetch: service.fetch });
|
|
|
|
try {
|
|
const baseUrl = server.url.href.replace(/\/$/u, "");
|
|
const health = await fetchJson(`${baseUrl}/healthz`);
|
|
const models = await fetchJson(`${baseUrl}/v1/models`);
|
|
const echo = await fetch(`${baseUrl}/v1/responses`, {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json", authorization: "Bearer smoke-redacted" },
|
|
body: JSON.stringify({
|
|
model: config.modelId,
|
|
stream: true,
|
|
input: [{ role: "user", content: [{ type: "input_text", text: "ECHO sentinel-01" }] }],
|
|
}),
|
|
});
|
|
const echoText = await echo.text();
|
|
const events = parseSseEvents(echoText);
|
|
const nonEcho = await fetch(`${baseUrl}/v1/responses`, {
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({ model: config.modelId, stream: true, input: "hello" }),
|
|
});
|
|
const ok = health.ok === true
|
|
&& Array.isArray(models.data)
|
|
&& echo.ok
|
|
&& echo.headers.get("content-type")?.includes("text/event-stream") === true
|
|
&& events.some((event) => event.event === "response.output_text.delta" && event.data.delta === "sentinel-01")
|
|
&& events.some((event) => event.event === "response.completed")
|
|
&& nonEcho.status === 400;
|
|
console.log(JSON.stringify({
|
|
ok,
|
|
command: "fake-responses-provider-smoke",
|
|
baseUrl,
|
|
checks: {
|
|
health: health.ok === true,
|
|
models: Array.isArray(models.data),
|
|
echoStatus: echo.status,
|
|
echoDelta: events.find((event) => event.event === "response.output_text.delta")?.data.delta ?? null,
|
|
completed: events.some((event) => event.event === "response.completed"),
|
|
nonEchoStatus: nonEcho.status,
|
|
},
|
|
valuesPrinted: false,
|
|
}, null, 2));
|
|
process.exitCode = ok ? 0 : 1;
|
|
} finally {
|
|
server.stop(true);
|
|
}
|
|
|
|
async function fetchJson(url: string): Promise<Record<string, unknown>> {
|
|
const response = await fetch(url);
|
|
const parsed = await response.json() as unknown;
|
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed as Record<string, unknown> : {};
|
|
}
|
|
|
|
function parseSseEvents(text: string): Array<{ event: string; data: Record<string, unknown> }> {
|
|
return text
|
|
.split(/\n\n/u)
|
|
.map((chunk) => chunk.trim())
|
|
.filter(Boolean)
|
|
.flatMap((chunk) => {
|
|
const event = /^event:\s*(.+)$/mu.exec(chunk)?.[1] ?? "message";
|
|
const dataLine = /^data:\s*(.+)$/mu.exec(chunk)?.[1] ?? "";
|
|
if (dataLine === "[DONE]" || dataLine.length === 0) return [];
|
|
try {
|
|
const parsed = JSON.parse(dataLine) as unknown;
|
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
? [{ event, data: parsed as Record<string, unknown> }]
|
|
: [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
});
|
|
}
|