mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
open_ai: Fix error message not showing up when using ChatGPT subscription (#57750)
The API seems to return nested errors, so made the error deserialise
properly in case we get `{ "error": {...} }` instead of a top-level
error
Closes #57024
For testing, you can prompt something like: `tell me about
https://registry.npmjs.org/vite-plus.`
Before:
<img width="631" height="69" alt="image"
src="https://github.com/user-attachments/assets/5d02e7ec-8176-4bff-87d7-908ac8f0b498"
/>
After:
<img width="697" height="61" alt="image"
src="https://github.com/user-attachments/assets/97fac249-8b76-463c-8483-a150f5db9857"
/>
Release Notes:
- openai: Fixed an issue where error messages would not show up properly
This commit is contained in:
parent
5e717a06cd
commit
88a54a2683
2 changed files with 73 additions and 3 deletions
|
|
@ -881,8 +881,13 @@ impl OpenAiResponseEventMapper {
|
|||
let message = response_failure_message(&response);
|
||||
vec![Err(LanguageModelCompletionError::Other(anyhow!(message)))]
|
||||
}
|
||||
ResponsesStreamEvent::Error { error }
|
||||
| ResponsesStreamEvent::GenericError { error } => {
|
||||
ResponsesStreamEvent::Error { error } => {
|
||||
vec![Err(LanguageModelCompletionError::Other(anyhow!(
|
||||
response_error_message(&error)
|
||||
)))]
|
||||
}
|
||||
ResponsesStreamEvent::GenericError { error } => {
|
||||
let error = error.into_response_error();
|
||||
vec![Err(LanguageModelCompletionError::Other(anyhow!(
|
||||
response_error_message(&error)
|
||||
)))]
|
||||
|
|
@ -2214,6 +2219,34 @@ mod tests {
|
|||
assert_eq!(error.to_string(), "ERR_SOMETHING: Something went wrong");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn responses_stream_deserializes_nested_error_event() {
|
||||
// In practice the Responses API often nests error fields under an
|
||||
// `error` object even though the public spec documents them at the top
|
||||
// level. Make sure we don't lose the message and code in that case.
|
||||
let event = serde_json::from_value::<ResponsesStreamEvent>(json!({
|
||||
"type": "error",
|
||||
"error": {
|
||||
"type": "invalid_request_error",
|
||||
"code": "context_length_exceeded",
|
||||
"message": "Your input exceeds the context window of this model. Please adjust your input and try again.",
|
||||
"param": "input"
|
||||
},
|
||||
"sequence_number": 2
|
||||
}))
|
||||
.expect("nested error event");
|
||||
|
||||
let mut mapper = OpenAiResponseEventMapper::new();
|
||||
let mapped = mapper.map_event(event);
|
||||
|
||||
assert_eq!(mapped.len(), 1);
|
||||
let error = mapped.into_iter().next().unwrap().unwrap_err();
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"context_length_exceeded: Your input exceeds the context window of this model. Please adjust your input and try again."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn responses_stream_deserializes_response_error_event() {
|
||||
let event = serde_json::from_value::<ResponsesStreamEvent>(json!({
|
||||
|
|
|
|||
|
|
@ -158,6 +158,43 @@ pub struct ResponseError {
|
|||
pub param: Option<Value>,
|
||||
}
|
||||
|
||||
/// Payload of the top-level `error` SSE event from the Responses API.
|
||||
///
|
||||
/// OpenAI's spec documents the error fields as being at the top level of the
|
||||
/// event, but in practice the API often nests them under an `error` object.
|
||||
#[derive(Deserialize, Debug, Clone, Default)]
|
||||
pub struct GenericStreamErrorPayload {
|
||||
#[serde(flatten)]
|
||||
top_level: PartialResponseError,
|
||||
#[serde(default)]
|
||||
error: Option<PartialResponseError>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default)]
|
||||
struct PartialResponseError {
|
||||
#[serde(default)]
|
||||
code: Option<String>,
|
||||
#[serde(default)]
|
||||
message: Option<String>,
|
||||
#[serde(default)]
|
||||
param: Option<Value>,
|
||||
}
|
||||
|
||||
impl GenericStreamErrorPayload {
|
||||
pub fn into_response_error(self) -> ResponseError {
|
||||
let nested = self.error.unwrap_or_default();
|
||||
ResponseError {
|
||||
code: self.top_level.code.or(nested.code),
|
||||
message: self
|
||||
.top_level
|
||||
.message
|
||||
.or(nested.message)
|
||||
.unwrap_or_default(),
|
||||
param: self.top_level.param.or(nested.param),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum StreamEvent {
|
||||
|
|
@ -278,7 +315,7 @@ pub enum StreamEvent {
|
|||
#[serde(rename = "error")]
|
||||
GenericError {
|
||||
#[serde(flatten)]
|
||||
error: ResponseError,
|
||||
error: GenericStreamErrorPayload,
|
||||
},
|
||||
#[serde(other)]
|
||||
Unknown,
|
||||
|
|
|
|||
Loading…
Reference in a new issue