From 3a8575b4295747de6f98c566f3658f296b547272 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 20 Mar 2026 14:33:36 -0400 Subject: [PATCH] agents: fix vllm crash on malformed tool args, always use API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes: 1. Sanitize tool call arguments before pushing to conversation history — vllm re-parses them as JSON on the next request and crashes on invalid JSON from a previous turn. Malformed args now get replaced with {} and the model gets an error message telling it to retry with valid JSON. 2. Remove is_split special case — split goes through the normal job_consolidation_agent path like all other agents. 3. call_for_def always uses API when api_base_url is configured, regardless of tools field. Remove tools field from all .agent files — memory tools are always provided by the API layer. Also adds prompt size guard (800KB max) to catch oversized prompts before they hit the model context limit. Co-Authored-By: Claude Opus 4.6 (1M context) --- poc-memory/src/agents/api.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/poc-memory/src/agents/api.rs b/poc-memory/src/agents/api.rs index 7dee5b3..4df4810 100644 --- a/poc-memory/src/agents/api.rs +++ b/poc-memory/src/agents/api.rs @@ -70,8 +70,21 @@ pub async fn call_api_with_tools( let has_tools = msg.tool_calls.as_ref().is_some_and(|tc| !tc.is_empty()); if has_tools { - // Push the assistant message with tool calls - messages.push(msg.clone()); + // Push the assistant message with tool calls. + // Sanitize arguments: vllm re-parses them as JSON when + // preprocessing the conversation, so invalid JSON from the + // model crashes the next request. + let mut sanitized = msg.clone(); + if let Some(ref mut calls) = sanitized.tool_calls { + for call in calls { + if serde_json::from_str::(&call.function.arguments).is_err() { + log(&format!("sanitizing malformed args for {}: {}", + call.function.name, &call.function.arguments)); + call.function.arguments = "{}".to_string(); + } + } + } + messages.push(sanitized); // Execute each tool call for call in msg.tool_calls.as_ref().unwrap() { @@ -79,8 +92,17 @@ pub async fn call_api_with_tools( call.function.name, &call.function.arguments)); - let args: serde_json::Value = serde_json::from_str(&call.function.arguments) - .unwrap_or_default(); + let args: serde_json::Value = match serde_json::from_str(&call.function.arguments) { + Ok(v) => v, + Err(_) => { + log(&format!("malformed tool call args: {}", &call.function.arguments)); + messages.push(Message::tool_result( + &call.id, + "Error: your tool call had malformed JSON arguments. Please retry with valid JSON.", + )); + continue; + } + }; let output = if call.function.name.starts_with("memory_") { let prov = format!("agent:{}", agent);