fix(ai): prefix HTTP status codes onto Azure OpenAI and OpenAI Responses error messages so auto-retry fires on 5xx/429
closes #4232
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Azure OpenAI Responses and OpenAI Responses error formatting to prefix HTTP status codes onto `errorMessage`, so transient 5xx and 429 errors are correctly matched by the agent-level auto-retry classifier ([#4232](https://github.com/earendil-works/pi/issues/4232)).
|
||||
- Fixed Xiaomi MiMo model metadata to use the OpenAI-compatible endpoints and `openai-completions` API, restoring multi-turn thinking/tool-call sessions ([#4505](https://github.com/earendil-works/pi/issues/4505)).
|
||||
- Fixed OpenCode Go Kimi reasoning replay by normalizing streamed `reasoning` fields back to `reasoning_content` for OpenCode Go only ([#4251](https://github.com/earendil-works/pi/issues/4251)).
|
||||
|
||||
|
||||
@@ -40,6 +40,22 @@ function resolveDeploymentName(model: Model<"azure-openai-responses">, options?:
|
||||
return mappedDeployment || model.id;
|
||||
}
|
||||
|
||||
function formatAzureOpenAIError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
const status = (error as Error & { status?: unknown }).status;
|
||||
const statusCode = typeof status === "number" ? status : undefined;
|
||||
if (statusCode !== undefined) {
|
||||
return `Azure OpenAI API error (${statusCode}): ${error.message}`;
|
||||
}
|
||||
return error.message;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(error);
|
||||
} catch {
|
||||
return String(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Azure OpenAI Responses-specific options
|
||||
export interface AzureOpenAIResponsesOptions extends StreamOptions {
|
||||
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
@@ -119,7 +135,7 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
||||
delete (block as { partialJson?: string }).partialJson;
|
||||
}
|
||||
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
||||
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
output.errorMessage = formatAzureOpenAIError(error);
|
||||
stream.push({ type: "error", reason: output.stopReason, error: output });
|
||||
stream.end();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,22 @@ function getPromptCacheRetention(
|
||||
return cacheRetention === "long" && compat.supportsLongCacheRetention ? "24h" : undefined;
|
||||
}
|
||||
|
||||
function formatOpenAIResponsesError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
const status = (error as Error & { status?: unknown }).status;
|
||||
const statusCode = typeof status === "number" ? status : undefined;
|
||||
if (statusCode !== undefined) {
|
||||
return `OpenAI API error (${statusCode}): ${error.message}`;
|
||||
}
|
||||
return error.message;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(error);
|
||||
} catch {
|
||||
return String(error);
|
||||
}
|
||||
}
|
||||
|
||||
// OpenAI Responses-specific options
|
||||
export interface OpenAIResponsesOptions extends StreamOptions {
|
||||
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
@@ -130,7 +146,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIRes
|
||||
delete (block as { partialJson?: string }).partialJson;
|
||||
}
|
||||
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
||||
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
output.errorMessage = formatOpenAIResponsesError(error);
|
||||
stream.push({ type: "error", reason: output.stopReason, error: output });
|
||||
stream.end();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user