43 lines
2.7 KiB
TypeScript
43 lines
2.7 KiB
TypeScript
// Translate existing UI scenarios into Responses wire fixtures. Production
|
|
// clients accept Responses only; this helper belongs exclusively to tests.
|
|
export function responseFixtureWriter(conversationId?: string) {
|
|
let sequence = 0;
|
|
let id = "resp_browser_fixture";
|
|
let messageId = "msg_browser_fixture";
|
|
const texts = new Map<string, string>();
|
|
const contentIndices = new Map<string, number>();
|
|
const closed = new Set<string>();
|
|
let error: string | undefined;
|
|
const event = (type: string, fields: Record<string, unknown>) => `event: ${type}\ndata: ${JSON.stringify({ type, sequence_number: sequence++, ...fields })}\n\n`;
|
|
const textFields = (key: string) => ({ item_id: messageId, output_index: 0, content_index: contentIndices.get(key) ?? 0 });
|
|
return (chunk: Record<string, unknown>) => {
|
|
if (chunk.type === "start") {
|
|
messageId = String(chunk.messageId); id = `resp_${messageId}`;
|
|
return event("response.created", { response: { id, object: "response", status: "in_progress", ...(conversationId ? { conversation: { id: conversationId } } : {}) } })
|
|
+ event("response.output_item.added", { output_index: 0, item: { type: "message", role: "assistant", id: messageId, content: [] } });
|
|
}
|
|
if (chunk.type === "text-start") {
|
|
const key = String(chunk.id);
|
|
contentIndices.set(key, contentIndices.size); texts.set(key, "");
|
|
return event("response.content_part.added", { ...textFields(key), part: { type: "output_text", text: "" } });
|
|
}
|
|
if (chunk.type === "text-delta") {
|
|
const key = String(chunk.id); texts.set(key, `${texts.get(key) ?? ""}${String(chunk.delta)}`);
|
|
return event("response.output_text.delta", { ...textFields(key), delta: chunk.delta });
|
|
}
|
|
if (chunk.type === "text-end") { const key = String(chunk.id); closed.add(key); return event("response.output_text.done", { ...textFields(key), text: texts.get(key) ?? "" }); }
|
|
if (typeof chunk.type === "string" && chunk.type.startsWith("data-")) return event(`tjwater.${chunk.type.slice(5)}`, { response_id: id, data: chunk.data, ...(chunk.id ? { id: chunk.id } : {}) });
|
|
if (chunk.type === "error") { error = String(chunk.errorText); return ""; }
|
|
if (chunk.type === "finish") {
|
|
const rest = [...texts.keys()].filter((key) => !closed.has(key)).map((key) => event("response.output_text.done", { ...textFields(key), text: texts.get(key) })).join("");
|
|
return rest + event(error ? "response.failed" : "response.completed", { response: { id, object: "response", status: error ? "failed" : "completed", ...(error ? { error: { message: error } } : {}) } });
|
|
}
|
|
return "";
|
|
};
|
|
}
|
|
|
|
export function responsesFixture(chunks: Record<string, unknown>[]) {
|
|
const write = responseFixtureWriter();
|
|
return chunks.map(write).join("");
|
|
}
|