Summary
Maka crashes with "未知错误 / Operation failed" mid-stream whenever a custom OpenAI-compatible connection streams tool calls whose index is not contiguous from 0. Reproduces 100% with an OpenAI-compatible gateway that translates Anthropic streaming to OpenAI chat-completions format.
Environment
- Maka desktop (Electron, com.maka.desktop)
- Connection type: "自定义中转站(OpenAI Chat)" (Custom relay, OpenAI Chat-compatible), i.e.
/v1/chat/completions - Model: claude-opus-4-8 (via gateway)
- Bundled SDK:
@ai-sdk/openai-compatible 3.0.12, ai 7.0.31 (extracted from app.asar)
Reproduction
- Configure a custom OpenAI Chat-compatible connection pointing at a gateway that emits streamed
tool_calls with non-zero-starting indices (e.g. an Anthropic→OpenAI streaming translator that uses the Anthropic content-block index as the OpenAI tool_calls[].index). - Start an agent-mode conversation so the model emits a text block followed by a
tool_use block. - The gateway emits
choices[0].delta.tool_calls[0].index = 1 (text block consumed index 0). - Maka's stream errors out with "Operation failed" / "未知错误 / 已保留部分输出".
Root cause
@ai-sdk/openai-compatible 3.0.12's StreamingToolCallTracker (in @ai-sdk/provider-utils):
// processDeltaconstindex=toolCallDelta.index??this.toolCalls.length;if(this.toolCalls[index]==null)this.processNewToolCall(index,toolCallDelta);
It writes tool calls into the array by their reported index (this.toolCalls[1] = ...), leaving slot 0 as an empty hole. Then flush() iterates the array and reads toolCall.hasFinished on every entry — the empty slot is undefined, so it throws:
TypeError: Cannot read properties of undefined (reading 'hasFinished')
at StreamingToolCallTracker.flush (@ai-sdk/provider-utils/dist/index.js:3570)
at Object.flush (@ai-sdk/openai-compatible/dist/index.js:896)
OpenAI's spec says tool-call indices start at 0 and increment by 1, but real-world gateways (Anthropic→OpenAI translators, aggregators, load balancers) do not always guarantee contiguous indices. The tracker should tolerate gaps (skip null/undefined entries in flush, or use optional chaining) — other clients (e.g. opencode's built-in openai-compatible parser) do exactly that and never crash on the same stream.
Impact
Any tool call in agent mode through such a gateway fails the entire turn. Pure-text turns work; models that don't emit tool_use blocks never trigger it.
Expected behavior
Streamed tool calls with non-contiguous or non-zero indices should be handled gracefully (skip empty slots), not crash the whole stream.
Summary
Maka crashes with "未知错误 / Operation failed" mid-stream whenever a custom OpenAI-compatible connection streams tool calls whose
indexis not contiguous from 0. Reproduces 100% with an OpenAI-compatible gateway that translates Anthropic streaming to OpenAI chat-completions format.Environment
/v1/chat/completions@ai-sdk/openai-compatible3.0.12,ai7.0.31 (extracted from app.asar)Reproduction
tool_callswith non-zero-starting indices (e.g. an Anthropic→OpenAI streaming translator that uses the Anthropic content-block index as the OpenAItool_calls[].index).tool_useblock.choices[0].delta.tool_calls[0].index = 1(text block consumed index 0).Root cause
@ai-sdk/openai-compatible3.0.12'sStreamingToolCallTracker(in@ai-sdk/provider-utils):It writes tool calls into the array by their reported
index(this.toolCalls[1] = ...), leaving slot 0 as an empty hole. Thenflush()iterates the array and readstoolCall.hasFinishedon every entry — the empty slot isundefined, so it throws:OpenAI's spec says tool-call indices start at 0 and increment by 1, but real-world gateways (Anthropic→OpenAI translators, aggregators, load balancers) do not always guarantee contiguous indices. The tracker should tolerate gaps (skip
null/undefinedentries inflush, or use optional chaining) — other clients (e.g. opencode's built-in openai-compatible parser) do exactly that and never crash on the same stream.Impact
Any tool call in agent mode through such a gateway fails the entire turn. Pure-text turns work; models that don't emit
tool_useblocks never trigger it.Expected behavior
Streamed tool calls with non-contiguous or non-zero indices should be handled gracefully (skip empty slots), not crash the whole stream.