import { openWebSocket } from './websocket-client.mjs';
let session;
try {
session = await openWebSocket('responses');
const history = [];
const seenResponses = new Set();
for (const prompt of ['Suggest a short name for a coffee shop.', 'Explain that name in one sentence.']) {
history.push({ role: 'user', content: prompt });
await session.send({
type: 'response.create', model: session.model,
input: history, instructions: 'Answer briefly in plain text.',
store: false, include: ['reasoning.encrypted_content'],
});
let responseId;
const textParts = new Map();
const itemIds = new Map();
let textBytes = 0;
for (;;) {
const event = await session.receive();
if (event.type === 'response.created') {
const id = event.response?.id;
if (responseId || typeof id !== 'string' || !id || seenResponses.has(id)) throw new Error('Invalid response identity.');
responseId = id;
seenResponses.add(id);
} else if (event.type === 'response.output_text.delta') {
if (!responseId || (event.response_id && event.response_id !== responseId) || typeof event.delta !== 'string'
|| typeof event.item_id !== 'string' || !event.item_id
|| !Number.isInteger(event.output_index) || event.output_index < 0
|| !Number.isInteger(event.content_index) || event.content_index < 0) throw new Error('Invalid text delta.');
const key = `${event.output_index}:${event.content_index}`;
if (itemIds.has(event.output_index) && itemIds.get(event.output_index) !== event.item_id) throw new Error('Mixed output items.');
itemIds.set(event.output_index, event.item_id);
textParts.set(key, (textParts.get(key) ?? '') + event.delta);
textBytes += Buffer.byteLength(event.delta);
if (textBytes > 1024 * 1024) throw new Error('Text limit exceeded.');
} else if (['response.completed', 'response.done'].includes(event.type)) {
const result = event.response;
if (!responseId || result?.id !== responseId || result.status !== 'completed' || result.error
|| !Array.isArray(result.output) || !result.output.length) throw new Error('Response did not complete.');
const finalParts = new Map();
for (const [index, item] of result.output.entries()) {
if (item.type === 'reasoning') continue;
if (item.type !== 'message' || item.id !== itemIds.get(index) || item.role !== 'assistant' || item.status !== 'completed'
|| !Array.isArray(item.content) || !item.content.length) throw new Error('Unsupported output or tool call.');
for (const [partIndex, part] of item.content.entries()) {
if (part.type !== 'output_text' || typeof part.text !== 'string') throw new Error('Refusal or invalid text.');
finalParts.set(`${index}:${partIndex}`, part.text);
}
}
if (finalParts.size !== textParts.size
|| [...finalParts].some(([key, text]) => textParts.get(key) !== text)) throw new Error('Final text differs from deltas.');
const text = [...finalParts.values()].join('\n');
if (!text.trim()) throw new Error('Empty response.');
// Replay every raw output item, preserving encrypted reasoning and metadata.
history.push(...result.output);
console.log(text);
break;
} else if (['response.failed', 'response.incomplete', 'response.cancelled', 'response.canceled'].includes(event.type)) {
throw new Error('Response ended without success.');
} else if (event.response_id && event.response_id !== responseId) {
throw new Error('Unexpected response identity.');
}
}
}
} catch {
console.error('Responses WebSocket failed. Check configuration, handshake, events, and deadline; no automatic retry.');
process.exitCode = 1;
} finally {
session?.close();
}