[Bug] Puter provider relays tool_calls without stringifying function.arguments → AI_TypeValidationError in opencode
Author: CrazyphilCreated Sep 24, 2026Updated Sep 24, 2026
Labelsbug
Before submitting ☑️ I checked Known Issues ☑️ I searched existing issues — found #3373 (same malformed shape, closed after an Ollama-worker-only fix; bug persists via the Puter provider)
Configuration (Required)
- Model:
z-ai:z-ai/glm-5.3(also reproduced:openrouter:~google/gemini-flash-latest,infron:google/gemini-3.8-flash:priority) - Provider:
Puter - Interface: API (
g4f api, OpenAI-compatible/v1/chat/completions)
Bug description Clear steps to reproduce:
- Exact command/file used:
curl -sN "https://puter.g4f-dev.workers.dev/chat/completions" \ -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \ -d '{"model":"z-ai:z-ai/glm-5.3","stream":true, "messages":[{"role":"user","content":"Call the bash tool to run: echo hello"}], "tools":[{"type":"function","function":{"name":"bash","description":"Run a bash command", "parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}}}]}' - Environment location: Germany
- Observed behavior vs expected:
- Observed: the streamed chunk delivers
delta.tool_calls[0].function.argumentsas a JSON object, the tool call has noindexfield, and the complete tool call plusfinish_reason:"stop"arrive in a single chunk:{"id":"chatcmpl-1790267014577","object":"chat.completion.chunk","created":1790267014, "model":"z-ai:z-ai/glm-5.3","choices":[{"index":0,"delta":{"tool_calls":[ {"id":"call_c0c7387a74ec4150a6586e15","type":"function", "function":{"name":"bash","arguments":{"command":"echo hello"}}}]}, "finish_reason":"stop"}]} - Expected:
function.argumentsas a JSON-encoded string ("arguments":"{\"command\":\"echo hello\"}"), per the OpenAI streaming schema. Strict clients (opencode via@ai-sdk/openai-compatible) reject the whole stream withAI_TypeValidationError: expected string, received object.
- Observed: the streamed chunk delivers
Environment
- Docker container running OmniRoute
- Direct connection using
ai-sdkto g4f Puter proxy (puter.g4f-dev.workers.dev)
Screenshots/Logs
AI_TypeValidationError: Type validation failed: Value: {"id":"chatcmpl-1790267014577",...,"choices":[{"index":0,"delta":{"tool_calls":[{"id":"call_c0c7387a74ec4150a6586e15","type":"function","function":{"name":"bash","arguments":{"command":"echo hello"}}}]},"finish_reason":"stop"}]}
Error message: [{"code":"invalid_union","errors":[[
{"expected":"string","code":"invalid_type","path":["choices",0,"delta","tool_calls",0,"function","arguments"],"message":"Invalid input: expected string, received object"}],[
{"expected":"object","code":"invalid_type","path":["error"],"message":"Invalid input: expected object, received undefined"}]],"path":[],"message":"Invalid input"}]No error is logged by the g4f API itself — it streams the chunk as if it were valid.
Additional context
- No proxy/VPN involved. Other providers on the same instance work; the issue is specific to providers that relay native upstream tool calls.
- Root cause pointer:
g4f/Provider/needs_auth/Puter.py(lines ~506–508) relays upstreamdelta.tool_callsverbatim —yield ToolCalls(choice["delta"]["tool_calls"])— without normalizingfunction.argumentsto a string (and without adding the streamingindexfield). g4f's own text-parsed tool path does this correctly vianormalize_tool_calls(g4f/tools/tool_support.py,json.dumps(args)), so only the native-relay path leaks the object form. - This is the same defect class as #3373, which was fixed only for the Ollama worker (commit 1448f7ad). The Puter relay path still emits the malformed shape as of 2026-09-24.
- Downstream impact: routing this through a gateway (OmniRoute) with strict-schema clients breaks all tool-calling workflows intermittently, since the malformed chunk is forwarded as-is. Filed downstream bug: diegosouzapw/OmniRoute#14786
Source: xtekky/gpt4free