{"slug": "qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between", "title": "Qwen Code's Multi-Protocol Agent Runtime: How One Terminal Agent Switches Between OpenAI, Anthropic, and Local Models at Runtime", "summary": "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.", "body_md": "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.\n\nThe 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.\n\nQwen 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.\n\n**Key components:**\n\n`tool_calls`, Anthropic's `content` blocks, or regex-parsed JSON from local models).\nWhen 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.\n\nHere's how a single tool definition flows through different providers:\n\n| Provider | Tool Schema Format | Tool Call Extraction | Fallback Behavior | \n|---|---|---|---|\n| OpenAI | `functions` or`tools` array | Parse `tool_calls` from response | Retry with plain JSON if model lacks tools | \n| Anthropic | `tools` array | Parse `content` blocks with`tool_use` | Retry with plain JSON if model lacks tools | \n| Gemini | `function_declarations` | Parse `functionCall` from response | Retry with plain JSON if model lacks tools | \n| Qwen API | `tools` array (OpenAI-like) | Parse `tool_calls` from response | Retry with plain JSON if model lacks tools | \n| Ollama | Plain JSON in system prompt | Regex parse JSON from text response | No fallback, fails if JSON is malformed | \n| vLLM | Plain JSON in system prompt | Regex parse JSON from text response | No fallback, fails if JSON is malformed | \n\nFor 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.\n\n**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:\n\n**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.\n\nSkill 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.\n\nSubAgents 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.\n\n**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.\n\nSubAgents 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.\n\nQwen 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.\n\nWhen 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.\n\nThe 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.\n\nQwen 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.\n\n**Credential management:**\n\n`~/.qwen-code/config.json` or environment variables.\nThe 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.\n\nThe 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.\n\n**Debugging flags:**\n\n`--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.\nThe agent does not expose metrics or telemetry by default. You can integrate with observability platforms (Datadog, Prometheus) by parsing the log files.\n\nQwen Code ships as:\n\nAll 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.\n\nThe 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.\n\n**Common failure modes:**\n\nThe 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.\n\nHere's how the agent switches providers mid-conversation:\n\n```\n// Internal provider adapter interface\ninterface ProviderAdapter {\n  name: string;\n  sendMessage(history: Message[], tools: Tool[]): Promise<Response>;\n  parseToolCalls(response: Response): ToolCall[];\n}\n\n// Switching providers\nasync function switchProvider(\n  session: Session,\n  newProvider: string\n): Promise<void> {\n  const adapter = providerRegistry.get(newProvider);\n  if (!adapter) throw new Error(`Unknown provider: ${newProvider}`);\n\n  // Re-serialize conversation history for new provider\n  const history = session.history.map(msg => \n    adapter.normalizeMessage(msg)\n  );\n\n  // Update session state\n  session.provider = newProvider;\n  session.history = history;\n  await session.save();\n}\n\n// Example: OpenAI to Anthropic\nconst session = await loadSession('abc123');\nawait switchProvider(session, 'anthropic');\nconst response = await session.sendMessage('Refactor this function');\n```\n\nThe `normalizeMessage` method rewrites message objects to match the new provider's schema. OpenAI uses `role` and `content`, Anthropic uses `role` and `content` arrays with `type` fields.\n\n**Use Qwen Code when:**\n\n**Avoid Qwen Code when:**\n\nThe multi-protocol abstraction is solid for prototyping and side projects. For production systems, you will need to add checkpointing, stronger sandboxing, and structured observability.", "url": "https://wpnews.pro/news/qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between", "canonical_source": "https://dev.to/mech_app_ai/qwen-codes-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between-openai-11l1", "published_at": "2026-10-30 20:09:16+00:00", "updated_at": "2026-10-30 20:20:41.716323+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models", "agent-protocols"], "entities": ["Qwen Code", "OpenAI", "Anthropic", "Google Gemini", "Ollama", "vLLM", "GitHub", "Qwen2.5-0.5B"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between", "markdown": "https://wpnews.pro/news/qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between.md", "text": "https://wpnews.pro/news/qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between.txt", "jsonld": "https://wpnews.pro/news/qwen-code-s-multi-protocol-agent-runtime-how-one-terminal-agent-switches-between.jsonld"}}