feat: add OpenAI responses wrapper
This commit is contained in:
+92
-1
@@ -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]");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user