TypeError in streamed tool-call reconstruction when decoded function arguments are null
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3582345. -->
Reported by: [merilainen](https://www.drupal.org/user/304437)
Related to !1377
>>>
<p>[Tracker]<br>
<strong>Update Summary: </strong>Patched streamed tool-call reconstruction to handle null/invalid decoded arguments and prevent a fatal TypeError.<br>
<strong>Short Description: </strong>Streamed tool-call handling can pass null arguments to ToolsFunctionOutput, causing a TypeError during chat stream reconstruction.<br>
<strong>Check-in Date: </strong>03/31/2026<br>
<em>Metadata is used by the <a href="https://www.drupalstarforge.ai/" title="AI Tracker">AI Tracker.</a> Docs and additional fields <a href="https://www.drupalstarforge.ai/ai-dashboard/docs" title="AI Issue Tracker Documentation">here</a>.</em><br>
[/Tracker]</p>
<h3 id="summary-problem-motivation">Problem/Motivation</h3>
<p>When AI tool calls are reconstructed from streamed chunks, function arguments are JSON-decoded from partial/aggregated stream data. In some cases, decoding returns null (for example empty/incomplete/non-object JSON).<br>
The streamed assembler then passes that null value into ToolsFunctionOutput::__construct(), where argument #3 is typed as array, triggering a fatal TypeError and breaking agent workflows.</p>
<p>Observed error:</p>
<p>TypeError: Drupal\ai\OperationType\Chat\Tools\ToolsFunctionOutput::__construct(): Argument #3 ($arguments) must be of type array, null given, called in /var/www/html/web/modules/contrib/ai/src/OperationType/Chat/StreamedChatMessageIterator.php on line 540 in Drupal\ai\OperationType\Chat\Tools\ToolsFunctionOutput->__construct() (line 45 of /var/www/html/web/modules/contrib/ai/src/OperationType/Chat/Tools/ToolsFunctionOutput.php).</p>
<h4 id="summary-steps-reproduce">Steps to reproduce (required for bugs, but not feature requests)</h4>
<p>Please provide information like AI modules enabled, which AI provider, browser, etc.</p>
<p>1. Enable AI module with tool-calling enabled and use any provider that supports streamed tool call chunks.<br>
2. Run an agent/tool-call scenario where tool-call arguments are streamed in partial chunks (or malformed/empty at intermediate stages).<br>
3. Let the stream complete so StreamedChatMessageIterator::assembleToolCalls() reconstructs tool calls.<br>
4. In affected cases, Json::decode(...) for arguments returns null.<br>
5. Stream reconstruction creates ToolsFunctionOutput with null as $arguments, causing a TypeError and aborting the response.</p>
<p>Environment details to include when reproducing:<br>
- Drupal core: 11.3.5<br>
- AI module version: 1.3.0<br>
- AI provider and model: GPT 5.2<br>
- Was using agent explorer</p>
<h3 id="summary-proposed-resolution">Proposed resolution</h3>
<p>Harden streamed tool-call reconstruction in StreamedChatMessageIterator::assembleToolCalls():</p>
<p>- Decode arguments with a safe fallback input: arguments ?? '{}'<br>
- Normalize decoded value:<br>
- If decoded result is an array, use it<br>
- Otherwise, use an empty array []<br>
- Apply this in both reconstruction points:<br>
- When flushing previous tool call on new tool id<br>
- When finalizing the last accumulated tool call</p>
<p>This ensures ToolsFunctionOutput always receives an array and prevents fatal errors from transient/invalid streamed argument payloads.</p>
<h3>Optional: Other details as applicable (e.g., User interface changes, API changes, Data model changes)</h3>
<p>- User interface changes: None.<br>
- API changes: None (internal robustness fix only).<br>
- Data model changes: None.<br>
- Backward compatibility: Preserved.</p>
<h3 id="summary-ai-usage">AI usage (if applicable)</h3>
<p>[x] AI Assisted Issue<br>
This issue was generated with AI assistance, but was reviewed and refined by the creator.</p>
<p>[x] AI Generated Code<br>
This code was mainly generated by an AI with human guidance, and reviewed, tested, and refined by a human.</p>
issue