From 29fe843dc5cd542813b153e477e8cb1dba40f2e2 Mon Sep 17 00:00:00 2001 From: ruttydm Date: Mon, 2 Mar 2026 23:14:17 +0100 Subject: [PATCH 1/2] fix: sanitize control characters in ToolCall::arguments() before json_decode Some providers (e.g. DeepSeek) may include raw control characters (0x00-0x1F, 0x7F) in streamed tool call argument JSON. These bytes are invalid per RFC 8259 and cause json_decode to throw a JsonException with "Control character error, possibly incorrectly encoded". Strip them before decoding. This mirrors the defensive approach already used in the OpenRouter streaming handler. Fixes #936 --- src/ValueObjects/ToolCall.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ValueObjects/ToolCall.php b/src/ValueObjects/ToolCall.php index 7329979ed..654e4ebc1 100644 --- a/src/ValueObjects/ToolCall.php +++ b/src/ValueObjects/ToolCall.php @@ -34,7 +34,10 @@ public function arguments(): array return []; } - $arguments = $this->arguments; + // Sanitize control characters that some providers (e.g. DeepSeek) may include + // in streamed tool call arguments. Raw 0x00-0x1F / 0x7F bytes are never valid + // in JSON (RFC 8259) and cause json_decode to throw "Control character error". + $arguments = preg_replace('/[\x00-\x1F\x7F]/', '', $this->arguments); return json_decode( $arguments, From 7e4d3a80a26fd1119ce4956e2748c19203198ba0 Mon Sep 17 00:00:00 2001 From: ruttydm Date: Tue, 31 Mar 2026 09:48:06 +0200 Subject: [PATCH 2/2] fix: cast preg_replace result to string for phpstan/rector compliance preg_replace() returns string|null, but json_decode() expects string. Add explicit (string) cast to satisfy both PHPStan and Rector's NullToStrictStringFuncCallArgRector rule. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/ValueObjects/ToolCall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ValueObjects/ToolCall.php b/src/ValueObjects/ToolCall.php index 654e4ebc1..2da29fa39 100644 --- a/src/ValueObjects/ToolCall.php +++ b/src/ValueObjects/ToolCall.php @@ -40,7 +40,7 @@ public function arguments(): array $arguments = preg_replace('/[\x00-\x1F\x7F]/', '', $this->arguments); return json_decode( - $arguments, + (string) $arguments, true, flags: JSON_THROW_ON_ERROR );