feat: add OpenAI responses wrapper

This commit is contained in:
2026-06-11 10:32:13 +01:00
parent ae61b4ce72
commit 189b3372a4
4 changed files with 283 additions and 4 deletions
+92 -1
View File
@@ -1 +1,92 @@
// OpenAI Responses API interface.
// OpenAI Responses API wrapper.
/**
* Send a request to the OpenAI Responses API and return the text result.
* @param {import("openai").OpenAI} client - Configured OpenAI SDK client.
* @param {{ input: unknown, model?: string, temperature?: number, maxOutputTokens?: number }} params - Request parameters.
* @returns {Promise<{ content: string, model?: string, usage?: object }>} Structured result.
*/
export async function sendOpenAIResponse(client, params) {
// --- Validation ---
if (!client || typeof client.responses?.create !== "function") {
const err = new Error("Invalid client: client.responses.create is required.");
err.kind = "ValidationError";
throw err;
}
if (!params || !params.input || !params.model) {
const err = new Error("Validation error: params.input and params.model are required.");
err.kind = "ValidationError";
throw err;
}
if (params.maxOutputTokens != null) {
const n = params.maxOutputTokens;
if (typeof n !== "number" || !Number.isInteger(n) || n <= 0) {
const err = new Error("Validation error: maxOutputTokens must be a positive integer.");
err.kind = "ValidationError";
throw err;
}
}
// --- Build request ---
const createParams = {
model: params.model,
input: params.input,
temperature: params.temperature,
};
if (params.maxOutputTokens != null) {
createParams.max_output_tokens = params.maxOutputTokens;
}
// --- Call API ---
let response;
try {
response = await client.responses.create(createParams);
} catch (error) {
return handleOpenAIError(error);
}
// --- Extract text ---
const content = response.output_text ?? "";
return {
content,
model: response.model ?? params.model,
usage: response.usage ?? null,
};
}
/**
* Map OpenAI SDK errors to safe, typed Error objects.
* @param {Error} error - The caught error from the SDK.
*/
function handleOpenAIError(error) {
const kind = getErrorKind(error);
const safeMessage = `OpenAI API error (${kind}): ${safeErrorMessage(error)}`;
const err = new Error(safeMessage);
err.kind = kind;
throw err;
}
function getErrorKind(error) {
if (error.status === 401 || /api[_-]?key/i.test(error.message ?? "")) {
return "OpenAIAuthError";
}
if (error.status === 429) {
return "OpenAIRateLimitError";
}
return "OpenAIRequestError";
}
function safeErrorMessage(error) {
const msg = String(error.message ?? "");
// Never leak API keys in error messages.
return msg.replace(/(api[_-]?key\s*[=:]\s*)\S+/gi, "$1[REDACTED]");
}