{"slug": "i-stopped-pretending-every-ai-provider-was-the-same", "title": "\"I Stopped Pretending Every AI Provider Was the Same\"", "summary": "A developer building CliGate, a local control plane for multiple AI coding tools, discovered that treating all AI providers as interchangeable leads to subtle failures. The project shifted from universal passthrough routing to capability-aware routing, where protocol translation is integrated into routing decisions. This approach prevents silent bugs by normalizing fields based on each provider's actual capabilities.", "body_md": "The easiest way to make an AI gateway feel flaky is to pretend every upstream model works the same way.\n\nOn paper, a lot of tools look compatible.\n\nThey all take a prompt. They all return text. Some of them even share an OpenAI-shaped API.\n\nIn practice, the differences show up exactly where users stop forgiving you:\n\nThat was one of the most useful lessons while building [CliGate](https://github.com/codeking-ai/cligate), my local control plane for Claude Code, Codex CLI, Gemini CLI, OpenClaw, a resident assistant, and multiple model/account sources behind one localhost entrypoint.\n\nThe bug was subtler than that.\n\nRouting often *did* succeed. A request got sent somewhere. A response came back. Nothing obviously crashed.\n\nBut that did not mean the gateway was correct.\n\nIf you route different tools and providers as if they were interchangeable, you get a class of failures that are hard to spot from logs alone:\n\nThat is not just transport routing.\n\nThat is capability routing.\n\nAt first, it is tempting to think routing is just:\n\n``` php\npick provider -> send request\n```\n\nThat model is too small.\n\nWhat actually mattered in CliGate was closer to this:\n\n``` php\nidentify caller/tool\n-> identify protocol shape\n-> resolve provider/model source\n-> apply capability profile\n-> translate or degrade fields safely\n-> send upstream\n```\n\nA provider being reachable is not enough.\n\nIt also needs to be treated according to the features it really supports.\n\nOne of the more useful internal lessons in this project is that protocol translation is not a separate cleanup step after routing.\n\nIt *is* part of routing.\n\nSome paths can accept a richer request shape. Some need fields normalized or stripped before the request becomes a silent bug.\n\nThat changed the safe mental model from:\n\n“upstream did not complain, so the route must be fine.”\n\nto:\n\n“this route supports a specific capability profile, so normalize on purpose.”\n\nThat sounds small, but it prevents a lot of “works sometimes” behavior.\n\nThis is the trap.\n\nLots of systems advertise compatibility because they accept a familiar endpoint shape.\n\nBut compatibility at the HTTP layer is only the beginning.\n\nIf one tool expects richer reasoning or metadata semantics and another backend treats those fields differently, the gateway has three bad choices:\n\nOnly the third one scales.\n\nThat is why I now prefer capability-aware routing over a universal passthrough design.\n\n`claude-code`\n\n, `codex`\n\n, `gemini-cli`\n\n, `openclaw`\n\n, and generic OpenAI/Anthropic-compatible clients may hit similar-looking routes, but they are not interchangeable from an operator’s perspective.\n\nThe user is often really asking for one of these:\n\nThat is why app-aware routing and capability-aware translation ended up being complementary, not separate concerns.\n\nOne decides **who this request is for**.\n\nThe other decides **how to make it truthful on the way through**.\n\nThe worst failures are the accidental ones.\n\nIf a gateway quietly forwards a field that the destination ignores, the user may never know why results became inconsistent.\n\nSo I started preferring explicit degradation rules.\n\nIf a route cannot honor a field, normalize it on purpose.\n\nIf a provider cannot match a capability, map it honestly.\n\nIf a model source is rate-limited or invalid, skip it instead of pretending all active-looking credentials are equal.\n\nThat gives me a much better operator story:\n\nA good gateway should hide repetitive setup work.\n\nIt should not lie about capability differences.\n\nOnce I accepted that, the architecture became cleaner:\n\nThat is less magical, but much more dependable.\n\nIf I were designing another AI gateway tomorrow, I would keep these rules:\n\nThat is the direction I have been pushing with CliGate.\n\nThe project still aims to give me one local place for model routing, accounts, API keys, local runtimes, channels, runtime sessions, and an assistant layer.\n\nBut the system became much more trustworthy once I stopped pretending every upstream provider was the same.\n\nIf you run multiple AI tools through one gateway, are you doing plain endpoint routing, or routing by actual capability too?", "url": "https://wpnews.pro/news/i-stopped-pretending-every-ai-provider-was-the-same", "canonical_source": "https://dev.to/codekingai/i-stopped-pretending-every-ai-provider-was-the-same-18k8", "published_at": "2026-06-20 12:10:47+00:00", "updated_at": "2026-06-20 12:36:50.069862+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-infrastructure", "ai-agents", "large-language-models"], "entities": ["CliGate", "Claude Code", "Codex CLI", "Gemini CLI", "OpenClaw", "OpenAI", "Anthropic"], "alternates": {"html": "https://wpnews.pro/news/i-stopped-pretending-every-ai-provider-was-the-same", "markdown": "https://wpnews.pro/news/i-stopped-pretending-every-ai-provider-was-the-same.md", "text": "https://wpnews.pro/news/i-stopped-pretending-every-ai-provider-was-the-same.txt", "jsonld": "https://wpnews.pro/news/i-stopped-pretending-every-ai-provider-was-the-same.jsonld"}}