Repository navigation
fix: keep streamed tool names from OpenAI-compatible routers - #351
Conversation
OpenAI-compatible gateways can send a tool call's name and id only on the first chat-completions delta, then resend both as empty strings while arguments continue. The accumulator treated those empty strings as updates, so web search ran as Tool ''. Co-authored-by: Taewan Park <Taewan-P@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to No unresolved merge-blocking issue is established in the reviewed streamed tool-call changes. Pre-merge checks |
|
|
Build complete! Here's the debug APK: https://github.com/Taewan-P/gpt_mobile/actions/runs/38019444272/artifacts/11657995786 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec2a2ba513
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
- Append streamed function-name fragments that repeat an earlier prefix, and only drop an exact retransmission or a longer cumulative name. Co-authored-by: Taewan Park <Taewan-P@users.noreply.github.com>
|
Build complete! Here's the debug APK: https://github.com/Taewan-P/gpt_mobile/actions/runs/38022377228/artifacts/11658104613 |
Fixes #350
Root cause
Web search on an OpenAI-compatible custom profile (the report used Clouvia Router) failed with
Tool '' is not assigned to this profileeven though the tool arguments were a validweb_searchpayload (query,maxResults). The same failure happened with Exa and Firecrawl and across models, so it was not a missing tool binding.Chat Completions streams from these routers send the function name and call id on the first
tool_callsdelta, then keep streaming argument fragments withfunction.nameand oftenidset to"".ChatCompletionsEventAssemblerstored every non-null name and id, and an empty string is non-null, so the real name was replaced. The arguments still accumulated, which matches the screenshot: a tool card with a blank name, a real call id when the id was not blanked, and arguments such as{"query":"today's AI news","maxResults":5}.AgentRunnerthen looked the tool up by that empty name and returned the assignment error. The follow-up request replayedfunction.name: "". Gateways commonly drop that connection instead of returning an HTTP error body, which Ktor surfaces asFailed to parse HTTP response: the server prematurely closed the connection. That second error is a consequence of the empty name, not a separate parser bug.Two related stream shapes drop the name the same way: the delta that carries the name omits
index(the chunk used to fail decoding and was skipped), or later argument deltas repeat the same call id under a different index.Fix
The chat-completions accumulator now:
indexand still joins argument deltas that share the call id, or that are argument-only fragments of the single open callA stream that never sends a real name still fails as an incomplete function call, rather than executing
Tool ''.Validation
Reproduced with decoded Chat Completions chunks in the shape those routers emit (name and id on the first delta,
""on the next, fullweb_searcharguments). Before the fix the assembler producedToolCall(callId=, name=, arguments={"query":"today's AI news","maxResults":5}), and the agent path never invokedweb_search. After the fix that stream executesweb_searchand the next round replays the original call id and name.Also covered: omitted index, same id under another index, argument fragments on a new index, split and repeated names, and parallel calls whose continuation names are blank.
./gradlew :app:testDebugUnitTest :app:lintDebugpassed (730 unit tests, 0 failures). ktlint 1.3.1 is clean on the changed Kotlin files.Summary by CodeRabbit