Qwen Code's Multi-Protocol Agent Runtime: How One Terminal Agent Switches Between OpenAI, Anthropic, and Local Models at Runtime The Qwen Code project has built a terminal-based AI coding agent that switches between OpenAI, Anthropic, Gemini, Qwen APIs and local models such as Ollama and vLLM at runtime without rewriting tool definitions or restarting the session. A provider abstraction layer normalizes tool schemas and response formats, re-serializing conversation history into each provider's message structure, while falling back to regex-parsed JSON for local models that lack structured output support. The agent also ships Auto-Memory backed by a local SQLite database, runtime-generated Auto-Skills, SubAgents and Agent Teams, and has reached 28.8K GitHub stars. Qwen Code is a terminal-based AI coding agent that lets you switch between OpenAI, Anthropic, Gemini, Qwen APIs, and local models Ollama, vLLM without rewriting tool definitions or restarting the session. It ships with Auto-Memory, Auto-Skills, SubAgents, Agent Teams, and MCP support. The project has 28.8K stars and is trending 9 on GitHub for TypeScript. The team uses the agent to file issues, submit PRs, and review code on its own repository. The interesting plumbing is how it maintains state and context when you swap providers mid-conversation, and how the same tool definitions work across OpenAI function calling, Anthropic tool use, and local model APIs that may not support structured outputs. Qwen Code uses a provider abstraction layer that normalizes tool definitions and response formats across different LLM APIs. The agent does not call OpenAI or Anthropic directly. Instead, it routes requests through a unified interface that translates tool schemas and response payloads. Key components: tool calls , Anthropic's content blocks, or regex-parsed JSON from local models . When you switch providers, the agent re-serializes the conversation history into the new provider's format. OpenAI and Anthropic use different message structures for tool calls, so the adapter rewrites the history array before sending the next request. Here's how a single tool definition flows through different providers: | Provider | Tool Schema Format | Tool Call Extraction | Fallback Behavior | |---|---|---|---| | OpenAI | functions or tools array | Parse tool calls from response | Retry with plain JSON if model lacks tools | | Anthropic | tools array | Parse content blocks with tool use | Retry with plain JSON if model lacks tools | | Gemini | function declarations | Parse functionCall from response | Retry with plain JSON if model lacks tools | | Qwen API | tools array OpenAI-like | Parse tool calls from response | Retry with plain JSON if model lacks tools | | Ollama | Plain JSON in system prompt | Regex parse JSON from text response | No fallback, fails if JSON is malformed | | vLLM | Plain JSON in system prompt | Regex parse JSON from text response | No fallback, fails if JSON is malformed | For local models, the agent injects a system prompt that describes available tools as JSON schemas and instructs the model to return tool calls in a specific format. The response parser uses regex to extract JSON blocks. If the model returns malformed JSON, the agent retries once with a clarification prompt. Auto-Memory persists conversation history, tool results, and user preferences in a local SQLite database. Each session has a unique ID. When you switch providers, the agent loads the session history and re-serializes it for the new provider. Memory entries include: Auto-Skills generates new tool definitions at runtime based on repeated patterns. If the agent detects that you ask for the same multi-step workflow three times, it proposes a new skill. The skill is stored as a JSON file in ~/.qwen-code/skills/ and registered in the tool schema normalizer. The next time you invoke that workflow, the agent calls the skill directly instead of re-planning. Skill generation uses a separate LLM call with a prompt that includes the conversation history and asks the model to extract a reusable function signature. The agent validates the generated schema and tests it once before persisting. SubAgents are child agent instances that run in isolated contexts. The parent agent spawns a SubAgent by calling a special tool spawn subagent with a task description and optional provider override. The SubAgent runs its own conversation loop and returns a final result to the parent. Agent Teams are collections of SubAgents with different roles planner, coder, reviewer . The parent agent routes tasks to the appropriate SubAgent based on a role classifier. The classifier is a small local model Qwen2.5-0.5B that runs inference in under 50ms. If the classifier is unavailable, the agent falls back to keyword matching. SubAgents share the same tool registry as the parent but maintain separate conversation histories. If a SubAgent switches providers, it does not affect the parent's provider state. Qwen Code supports the Model Context Protocol MCP for integrating external tools. MCP servers expose tools as JSON-RPC endpoints. The agent discovers available tools by calling the server's tools/list method and registers them in the tool schema normalizer. When the agent invokes an MCP tool, it sends a JSON-RPC request to the server and waits for the response. The response is appended to the conversation history as a tool result. MCP tools can be stateful the server maintains state between calls or stateless. The agent does not validate MCP tool schemas. If the server returns a malformed response, the agent logs the error and continues. This can cause the agent to hallucinate tool results. Qwen Code runs tool calls in a sandboxed subprocess. The sandbox uses Node.js's vm module to isolate tool execution. File system access is restricted to the current working directory. Network access is unrestricted. Credential management: ~/.qwen-code/config.json or environment variables. The sandbox does not prevent tools from spawning child processes or making network requests. A malicious tool can exfiltrate data or execute arbitrary code. The agent logs all tool calls and results, but does not block suspicious behavior. The agent logs all LLM requests, tool calls, and state transitions to ~/.qwen-code/logs/ . Logs are structured JSON with timestamps, session IDs, and provider names. You can tail the log file to watch the agent's decision-making in real time. Debugging flags: --debug : Enables verbose logging includes full request/response payloads . --trace : Enables trace-level logging includes internal state changes . --dry-run : Simulates tool calls without executing them. The agent does not expose metrics or telemetry by default. You can integrate with observability platforms Datadog, Prometheus by parsing the log files. Qwen Code ships as: All deployment shapes share the same agent core. The CLI and desktop app run the agent locally. The web UI and chat integrations connect to a remote agent server via WebSocket. The IDE plugins use language server protocol LSP to communicate with the agent. The agent server is a Node.js HTTP server that exposes a REST API for starting sessions, sending messages, and retrieving history. WebSocket connections are used for streaming responses. Common failure modes: The agent does not checkpoint state during long-running tasks. If the process crashes, you lose the current session. You can resume from the last persisted message in the SQLite database, but tool results are not replayed. Here's how the agent switches providers mid-conversation: // Internal provider adapter interface interface ProviderAdapter { name: string; sendMessage history: Message , tools: Tool : Promise