From 086418eb5d5125c4f4d07966a53811f13dc14488 Mon Sep 17 00:00:00 2001 From: Joseph Ivan Obala Date: Thu, 26 Mar 2026 16:49:54 +0300 Subject: [PATCH] fix(groq): handle Llama models embedding arguments in function name Llama models running on Groq (e.g. llama-3.3-70b-versatile) occasionally return tool calls where the entire argument payload is concatenated into the function.name field: "function": { "name": "get_transactions,{\"from_date\":\"2026-03-06\"}", "arguments": "" } Prism passes this mangled string as the ToolCall name. On the follow-up turn Groq validates the assistant message's tool_calls against the original request.tools list and rejects the request because "get_transactions,{...}" was never registered as a tool: Groq Error [400]: tool call validation failed: attempted to call tool 'get_transactions,{"from_date":"..."}' which was not in request.tools Fix: in mapToolCalls(), detect the "name,{...}" pattern, validate the suffix is valid JSON, and split into a clean name + arguments string. --- src/Providers/Groq/Handlers/Text.php | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Providers/Groq/Handlers/Text.php b/src/Providers/Groq/Handlers/Text.php index a88c3007e..b81c86e23 100644 --- a/src/Providers/Groq/Handlers/Text.php +++ b/src/Providers/Groq/Handlers/Text.php @@ -148,10 +148,28 @@ protected function addStep(array $data, Request $request, ClientResponse $client */ protected function mapToolCalls(array $toolCalls): array { - return array_map(fn (array $toolCall): ToolCall => new ToolCall( - id: data_get($toolCall, 'id'), - name: data_get($toolCall, 'function.name'), - arguments: data_get($toolCall, 'function.arguments'), - ), $toolCalls); + return array_map(function (array $toolCall): ToolCall { + $name = data_get($toolCall, 'function.name', ''); + $arguments = data_get($toolCall, 'function.arguments', '{}'); + + // Some Llama models (e.g. llama-3.3-70b-versatile on Groq) embed + // the arguments JSON directly in the function name field, separated + // by a comma: "tool_name,{\"arg\":\"val\"}". Groq then rejects the + // follow-up turn because the mangled name is not in request.tools. + // Detect this pattern and split the name from the inline arguments. + if (is_string($name) && str_contains($name, ',{')) { + [$extractedName, $inlineArgs] = explode(',', $name, 2); + if (json_decode($inlineArgs) !== null) { + $name = $extractedName; + $arguments = $inlineArgs; + } + } + + return new ToolCall( + id: data_get($toolCall, 'id'), + name: $name, + arguments: $arguments ?: '{}', + ); + }, $toolCalls); } }