More graceful invalid JSON handling (#29295)
Now we're more tolerant of invalid JSON coming back from the model (possibly because it was incomplete and we're streaming), plus if we do end up with invalid JSON once it has all streamed back, we report what the malformed JSON actually was: <img width="444" alt="Screenshot 2025-04-23 at 1 49 14 PM" src="https://github.com/user-attachments/assets/480f5da7-869b-49f3-9ffd-8f08ccddb33d" /> Release Notes: - N/A
This commit is contained in:
parent
92e810bfec
commit
f6774ae60d
1 changed files with 19 additions and 26 deletions
|
@ -714,39 +714,32 @@ pub fn map_to_language_model_completion_events(
|
|||
if let Some(tool_use) = state.tool_uses_by_index.get_mut(&index) {
|
||||
tool_use.input_json.push_str(&partial_json);
|
||||
|
||||
return Some((
|
||||
vec![maybe!({
|
||||
Ok(LanguageModelCompletionEvent::ToolUse(
|
||||
// Try to convert invalid (incomplete) JSON into
|
||||
// valid JSON that serde can accept, e.g. by closing
|
||||
// unclosed delimiters. This way, we can update the
|
||||
// UI with whatever has been streamed back so far.
|
||||
if let Ok(input) = serde_json::Value::from_str(
|
||||
&partial_json_fixer::fix_json(&tool_use.input_json),
|
||||
) {
|
||||
return Some((
|
||||
vec![Ok(LanguageModelCompletionEvent::ToolUse(
|
||||
LanguageModelToolUse {
|
||||
id: tool_use.id.clone().into(),
|
||||
name: tool_use.name.clone().into(),
|
||||
is_input_complete: false,
|
||||
input: if tool_use.input_json.is_empty() {
|
||||
serde_json::Value::Object(
|
||||
serde_json::Map::default(),
|
||||
)
|
||||
} else {
|
||||
serde_json::Value::from_str(
|
||||
// Convert invalid (incomplete) JSON into
|
||||
// JSON that serde will accept, e.g. by closing
|
||||
// unclosed delimiters. This way, we can update
|
||||
// the UI with whatever has been streamed back so far.
|
||||
&partial_json_fixer::fix_json(
|
||||
&tool_use.input_json,
|
||||
),
|
||||
)
|
||||
.map_err(|err| anyhow!(err))?
|
||||
},
|
||||
input,
|
||||
},
|
||||
))
|
||||
})],
|
||||
state,
|
||||
));
|
||||
))],
|
||||
state,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::ContentBlockStop { index } => {
|
||||
if let Some(tool_use) = state.tool_uses_by_index.remove(&index) {
|
||||
let input_json = tool_use.input_json.trim();
|
||||
|
||||
return Some((
|
||||
vec![maybe!({
|
||||
Ok(LanguageModelCompletionEvent::ToolUse(
|
||||
|
@ -754,15 +747,15 @@ pub fn map_to_language_model_completion_events(
|
|||
id: tool_use.id.into(),
|
||||
name: tool_use.name.into(),
|
||||
is_input_complete: true,
|
||||
input: if tool_use.input_json.is_empty() {
|
||||
input: if input_json.is_empty() {
|
||||
serde_json::Value::Object(
|
||||
serde_json::Map::default(),
|
||||
)
|
||||
} else {
|
||||
serde_json::Value::from_str(
|
||||
&tool_use.input_json,
|
||||
input_json
|
||||
)
|
||||
.map_err(|err| anyhow!(err))?
|
||||
.map_err(|err| anyhow!("Error parsing tool call input JSON: {err:?} - JSON string was: {input_json:?}"))?
|
||||
},
|
||||
},
|
||||
))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue