Fix: Handle PrismException during tool execution to allow LLM self-correction #833
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
🐛 Fix: Handle
PrismExceptionduring tool execution to allow LLM self-correctionProblem
When a
PrismExceptionoccurs during tool execution (e.g., tool not found, multiple tools with same name), the exception was thrown and broke the LLM conversation flow. This prevented the model from receiving feedback about the error and self-correcting.Example scenario:
"get_wether"instead of"get_weather"resolveTool()throwsPrismException::toolNotFound()Solution
Adopted the error handling approach from Anthropic's streaming handler: catch
PrismExceptionduring tool execution and convert it to a failedToolResultwith the error message. This allows the LLM to:Refactoring
While implementing this fix, refactored the duplicated tool execution logic into a centralized
callToolsAndYieldEvents()method in theCallsToolstrait:Before: Each of the 8 stream handlers had its own copy of tool execution + event generation.
After: Single
yield from $this->callToolsAndYieldEvents(...)call in each handlerGemini Stream Handler Fix
The Gemini Stream handler had inconsistent behavior, it wrapped string tool results in an array (
['result' => $output]) while the Gemini Text/Structured handlers did not. After reviewing the Gemini API function calling documentation and the codebase, confirmed thatMessageMap.phpalready wraps the tool result in acontentkey andjson_encode()s tool result when building the API request, so the additional array wrapping in the Stream handler was redundant. The Gemini Stream handler now usescallToolsAndYieldEvents()like all other providers, making tool result formatting consistent across all Gemini handlers.Changes
src/Concerns/CallsTools.phpcallToolsAndYieldEvents()withPrismExceptionhandling;callTools()now uses it internallysrc/Providers/*/Handlers/Stream.phpyield fromcalltests/Concerns/CallsToolsTest.phpTests Added
Added
tests/Concerns/CallsToolsTest.phpwith 9 tests covering:PrismExceptionhandling (tool not found, multiple tools found)PrismExceptionerrors are re-thrownBreaking Changes
None. This is a backward-compatible change:
callTools()method signature unchanged — existing Text/Structured handlers work without modificationPrismExceptionerrors still re-thrown as beforeResult
PrismExceptionerrors returned as tool results instead of thrown