fix(llm): preserve nested OpenAI stream errors (#36130)
Co-authored-by: Harsh Mathur <jeevesforharsh@gmail.com> Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
parent
0ac8f91ed6
commit
bd0dffd781
2 changed files with 70 additions and 10 deletions
|
|
@ -198,11 +198,11 @@ const OpenAIResponsesStreamItem = Schema.Struct({
|
|||
})
|
||||
type OpenAIResponsesStreamItem = Schema.Schema.Type<typeof OpenAIResponsesStreamItem>
|
||||
|
||||
// OpenAI Responses surfaces provider failures in two related shapes. The
|
||||
// streaming `error` event carries the details at the top level
|
||||
// (`{ type: "error", code, message, param, sequence_number }`), while
|
||||
// `response.failed` carries them under `response.error`. We capture both so
|
||||
// the parser can surface a useful provider-error message in either path.
|
||||
// The Responses schema puts streaming error details at the top level and
|
||||
// response failures under `response.error`. The official SDK also recognizes
|
||||
// an event-level HTTP-style `error` envelope, so accept all three shapes here.
|
||||
// https://github.com/openai/openai-openapi/blob/5162af98d3147432c14680df789e8e12d4891e6b/openapi.yaml#L67234-L67382
|
||||
// https://github.com/openai/openai-node/blob/61539248cbe04665de68a71e6fd878127ae4db87/src/core/streaming.ts#L58-L85
|
||||
const OpenAIResponsesErrorPayload = Schema.Struct({
|
||||
code: optionalNull(Schema.String),
|
||||
message: optionalNull(Schema.String),
|
||||
|
|
@ -227,9 +227,10 @@ const OpenAIResponsesEvent = Schema.Struct({
|
|||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
),
|
||||
),
|
||||
code: Schema.optional(Schema.String),
|
||||
code: optionalNull(Schema.String),
|
||||
message: Schema.optional(Schema.String),
|
||||
param: Schema.optional(Schema.String),
|
||||
param: optionalNull(Schema.String),
|
||||
error: optionalNull(OpenAIResponsesErrorPayload),
|
||||
})
|
||||
type OpenAIResponsesEvent = Schema.Schema.Type<typeof OpenAIResponsesEvent>
|
||||
|
||||
|
|
@ -899,7 +900,7 @@ const onResponseFinish = (state: ParserState, event: OpenAIResponsesEvent): Step
|
|||
// the bare message — production rate limits and context-length failures used
|
||||
// to be indistinguishable from generic stream drops.
|
||||
const providerErrorMessage = (event: OpenAIResponsesEvent, fallback: string): string => {
|
||||
const nested = event.response?.error ?? undefined
|
||||
const nested = event.error ?? event.response?.error ?? undefined
|
||||
const message = event.message || nested?.message || undefined
|
||||
const code = event.code || nested?.code || undefined
|
||||
if (message && code) return `${code}: ${message}`
|
||||
|
|
@ -907,7 +908,7 @@ const providerErrorMessage = (event: OpenAIResponsesEvent, fallback: string): st
|
|||
}
|
||||
|
||||
const providerError = (event: OpenAIResponsesEvent, fallback: string) => {
|
||||
const code = event.code || event.response?.error?.code || undefined
|
||||
const code = event.code || event.error?.code || event.response?.error?.code || undefined
|
||||
const message = providerErrorMessage(event, fallback)
|
||||
return LLMEvent.providerError({
|
||||
message,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue