Background
This came up while looking at #276 — Claude Code's web search was failing because the combo routed it to a provider that couldn't handle it. The immediate format detection and schema bugs are fixed in #397, but it got me thinking about a bigger question.
Right now, when an agent sends a built-in tool call (like web_search_20250305), 9router passes it through to whatever provider is handling the request. If that provider is Claude, it works — Claude knows how to handle its own tools. But if the combo falls through to Copilot, NVIDIA NIM, or any non-Claude provider, the tool call either fails silently or errors out.
The idea
What if 9router could route tool calls the same way it already routes chat completions?
The concept: when an agent requests a tool like web search, 9router intercepts it and translates it into the native tool call for whichever provider is configured to handle it. So if web search comes in and the user has Antigravity set as the tool provider, 9router translates the tool call into Antigravity's format — Antigravity processes it thinking it came from its own client, and 9router translates the response back. Same pattern 9router already uses for chat, just extended to tools.
The provider list wouldn't be limited to third-party search APIs — it would include the actual model providers too. Antigravity, Copilot, Kiro, Claude, etc. Each already has its own way of handling web search natively. 9router would just do the translation between formats, which it's already built to do.
Configuration could work like the existing Providers page — an ordered list of providers for each tool type, with fallback if the first one fails.
Where I'm stuck
The part I haven't figured out is the flow. Specifically:
- How do we keep this simple enough that it doesn't confuse users? Adding a whole new page for tool configuration could be overkill, or it could be exactly right — I'm not sure.
- Should tool routing be its own concept, or should it piggyback on the existing combo/provider system somehow?
- When should 9router intercept vs pass through? If the request is going to Claude and it's a Claude-native tool, intercepting is pointless overhead. But if it's going to Copilot, interception is the only way it works.
- How do we minimize complexity in the routing logic while still covering the common cases?
About me
I vibecode — Claude writes it, I review the approach and test everything on an isolated VM before pushing. My PRs on this repo so far have been small targeted fixes. This would be a bigger feature so I want to make sure the approach makes sense before writing anything.
@decolua — what do you think?
I wanted to get your take on this before going any further. Does this concept even make sense for 9router's direction? Is there a simpler way to solve the underlying problem that I'm overcomplicating? Would love to hear how you'd approach it — or if you think this isn't worth pursuing, that's useful to know too.
Open to ideas from anyone else who's run into this.
Background
This came up while looking at #276 — Claude Code's web search was failing because the combo routed it to a provider that couldn't handle it. The immediate format detection and schema bugs are fixed in #397, but it got me thinking about a bigger question.
Right now, when an agent sends a built-in tool call (like
web_search_20250305), 9router passes it through to whatever provider is handling the request. If that provider is Claude, it works — Claude knows how to handle its own tools. But if the combo falls through to Copilot, NVIDIA NIM, or any non-Claude provider, the tool call either fails silently or errors out.The idea
What if 9router could route tool calls the same way it already routes chat completions?
The concept: when an agent requests a tool like web search, 9router intercepts it and translates it into the native tool call for whichever provider is configured to handle it. So if web search comes in and the user has Antigravity set as the tool provider, 9router translates the tool call into Antigravity's format — Antigravity processes it thinking it came from its own client, and 9router translates the response back. Same pattern 9router already uses for chat, just extended to tools.
The provider list wouldn't be limited to third-party search APIs — it would include the actual model providers too. Antigravity, Copilot, Kiro, Claude, etc. Each already has its own way of handling web search natively. 9router would just do the translation between formats, which it's already built to do.
Configuration could work like the existing Providers page — an ordered list of providers for each tool type, with fallback if the first one fails.
Where I'm stuck
The part I haven't figured out is the flow. Specifically:
About me
I vibecode — Claude writes it, I review the approach and test everything on an isolated VM before pushing. My PRs on this repo so far have been small targeted fixes. This would be a bigger feature so I want to make sure the approach makes sense before writing anything.
@decolua — what do you think?
I wanted to get your take on this before going any further. Does this concept even make sense for 9router's direction? Is there a simpler way to solve the underlying problem that I'm overcomplicating? Would love to hear how you'd approach it — or if you think this isn't worth pursuing, that's useful to know too.
Open to ideas from anyone else who's run into this.