Default chat-only providers to Chat Completions

Route Nebius, Z.AI, Z.AI Coding, and Gemini API OAuth directly through Chat Completions. Avoid unsupported /responses probes and keep provider defaults aligned with documented upstream capabilities.

Alessandro committed Jul 31, 2026 at 18:17 UTC 0c663403a3cc7fc7256b0954b36180ae33dae693
5 files changed +84 -1
conf/AGENTS.md
+1
@@ -16,6 +16,7 @@
16 - Do not commit API keys, provider secrets, local account identifiers, or private endpoints.
17 - Keep provider IDs and settings keys stable unless all loaders, UI references, migrations, and tests are updated.
18 - Defaults must work in a clean checkout and in Docker.
19 +- Providers without a native Responses path in the supported LiteLLM runtime, or intentionally standardized on Chat Completions, must set `a0_api_mode: chat`; native Responses providers rely on the Responses default.
20 - Templates must avoid accidentally unignoring private runtime content.
21
22 ## Work Guidance
conf/model_providers.yaml
+29
@@ -32,6 +32,7 @@ chat:
32 models_list:
33 endpoint_url: "https://api.venice.ai/api/v1/models"
34 kwargs:
35 + a0_api_mode: chat
36 api_base: https://llm.agent-zero.ai/v1
37 venice_parameters:
38 include_venice_system_prompt: false
@@ -42,6 +43,8 @@ chat:
43 endpoint_url: "https://api.anthropic.com/v1/models"
44 params:
45 limit: "1000"
46 + kwargs:
47 + a0_api_mode: chat
48 cerebras:
49 name: Cerebras
50 litellm_provider: cerebras
@@ -55,11 +58,15 @@ chat:
58 litellm_provider: cometapi
59 models_list:
60 endpoint_url: "https://api.cometapi.com/v1/models"
61 + kwargs:
62 + a0_api_mode: chat
63 deepseek:
64 name: DeepSeek
65 litellm_provider: deepseek
66 models_list:
67 endpoint_url: "https://api.deepseek.com/models"
68 + kwargs:
69 + a0_api_mode: chat
70 github_copilot:
71 name: GitHub Copilot
72 litellm_provider: github_copilot
@@ -77,14 +84,20 @@ chat:
84 params:
85 pageSize: "1000"
86 default_base: "https://generativelanguage.googleapis.com"
87 + kwargs:
88 + a0_api_mode: chat
89 groq:
90 name: Groq
91 litellm_provider: groq
92 models_list:
93 endpoint_url: "https://api.groq.com/openai/v1/models"
94 + kwargs:
95 + a0_api_mode: chat
96 huggingface:
97 name: HuggingFace
98 litellm_provider: huggingface
99 + kwargs:
100 + a0_api_mode: chat
101 lm_studio:
102 name: LM Studio
103 litellm_provider: lm_studio
@@ -110,23 +123,30 @@ chat:
123 litellm_provider: mistral
124 models_list:
125 endpoint_url: "https://api.mistral.ai/v1/models"
126 + kwargs:
127 + a0_api_mode: chat
128 moonshot:
129 name: Moonshot AI
130 litellm_provider: moonshot
131 models_list:
132 endpoint_url: "https://api.moonshot.cn/v1/models"
133 + kwargs:
134 + a0_api_mode: chat
135 nebius:
136 name: Nebius Token Factory
137 litellm_provider: openai
138 models_list:
139 endpoint_url: "/models"
140 kwargs:
141 + a0_api_mode: chat
142 api_base: https://api.tokenfactory.nebius.com/v1
143 nvidia_nim:
144 name: NVIDIA NIM
145 litellm_provider: nvidia_nim
146 models_list:
147 endpoint_url: "https://integrate.api.nvidia.com/v1/models"
148 + kwargs:
149 + a0_api_mode: chat
150 ollama:
151 name: Ollama
152 litellm_provider: ollama
@@ -170,12 +190,15 @@ chat:
190 bedrock:
191 name: AWS Bedrock
192 litellm_provider: bedrock
193 + kwargs:
194 + a0_api_mode: chat
195 openrouter:
196 name: OpenRouter
197 litellm_provider: openrouter
198 models_list:
199 endpoint_url: "https://openrouter.ai/api/v1/models"
200 kwargs:
201 + a0_api_mode: chat
202 extra_headers:
203 "HTTP-Referer": "https://agent-zero.ai/"
204 "X-Title": "Agent Zero"
@@ -185,6 +208,8 @@ chat:
208 litellm_provider: sambanova
209 models_list:
210 endpoint_url: "https://api.sambanova.ai/v1/models"
211 + kwargs:
212 + a0_api_mode: chat
213 venice:
214 name: Venice.ai
215 litellm_provider: openai
@@ -210,12 +235,15 @@ chat:
235 litellm_provider: xai
236 models_list:
237 endpoint_url: "https://api.x.ai/v1/models"
238 + kwargs:
239 + a0_api_mode: chat
240 zai:
241 name: Z.AI
242 litellm_provider: openai
243 models_list:
244 endpoint_url: "/models"
245 kwargs:
246 + a0_api_mode: chat
247 api_base: https://api.z.ai/api/paas/v4
248 zai_coding:
249 name: Z.AI Coding
@@ -223,6 +251,7 @@ chat:
251 models_list:
252 endpoint_url: "/models"
253 kwargs:
254 + a0_api_mode: chat
255 api_base: https://api.z.ai/api/coding/paas/v4
256 other:
257 name: Other OpenAI compatible
plugins/_oauth/AGENTS.md
+1
@@ -46,6 +46,7 @@
46 - Codex Responses proxy requests must include Codex client metadata and compatibility headers such as `client_metadata`, `x-codex-installation-id`, `originator`, `session-id`, and `thread-id`, and must forward `input` as a list for upstream Codex compatibility.
47 - Codex Responses proxy requests must translate the legacy top-level `reasoning_effort` field to `reasoning.effort`; an explicit native `reasoning` field takes precedence.
48 - Codex Responses proxy defaults for reasoning effort, reasoning summary, and text verbosity come from the `codex` plugin config; explicit native request values take precedence.
49 +- OAuth providers without upstream Responses support must set `a0_api_mode: chat`; native Responses providers rely on the default, since a local proxy route alone does not prove upstream support.
50
51 ## Work Guidance
52
plugins/_oauth/conf/model_providers.yaml
+1
@@ -22,6 +22,7 @@ chat:
22 models_list:
23 endpoint_url: "/models"
24 kwargs:
25 + a0_api_mode: chat
26 api_base: "http://127.0.0.1/oauth/gemini-api/v1"
27 xai_grok_oauth:
28 name: xAI Grok Account
tests/test_model_config_api_keys.py
+52 -1
@@ -356,7 +356,7 @@ def test_direct_venice_chat_provider_defaults_to_chat_completions(monkeypatch):
356 assert venice["kwargs"]["venice_parameters"] == {
357 "include_venice_system_prompt": False
358 }
359 - assert "a0_api_mode" not in provider_config["chat"]["a0_venice"]["kwargs"]
359 + assert provider_config["chat"]["a0_venice"]["kwargs"]["a0_api_mode"] == "chat"
360 assert "a0_api_mode" not in provider_config["embedding"]["venice"]["kwargs"]
361
362 model = models.get_chat_model("venice", "llama-3.3-70b")
@@ -485,6 +485,57 @@ def test_local_chat_providers_default_to_chat_completions():
485 assert "a0_api_mode" not in provider_config["embedding"][provider]["kwargs"]
486
487
488 +def test_provider_api_mode_defaults_use_intended_transport():
489 + import yaml
490 +
491 + provider_config = yaml.safe_load(
492 + (PROJECT_ROOT / "conf" / "model_providers.yaml").read_text(encoding="utf-8")
493 + )
494 + oauth_provider_config = yaml.safe_load(
495 + (
496 + PROJECT_ROOT
497 + / "plugins"
498 + / "_oauth"
499 + / "conf"
500 + / "model_providers.yaml"
501 + ).read_text(encoding="utf-8")
502 + )
503 +
504 + chat_providers = (
505 + "anthropic",
506 + "cometapi",
507 + "deepseek",
508 + "google",
509 + "groq",
510 + "huggingface",
511 + "mistral",
512 + "moonshot",
513 + "nebius",
514 + "nvidia_nim",
515 + "bedrock",
516 + "openrouter",
517 + "sambanova",
518 + "xai",
519 + "zai",
520 + "zai_coding",
521 + )
522 + responses_providers = ("azure", "github_copilot", "openai")
523 +
524 + for provider in chat_providers:
525 + assert provider_config["chat"][provider]["kwargs"]["a0_api_mode"] == "chat"
526 +
527 + for provider in responses_providers:
528 + assert "a0_api_mode" not in provider_config["chat"][provider].get("kwargs", {})
529 +
530 + assert (
531 + oauth_provider_config["chat"]["gemini_api_oauth"]["kwargs"]["a0_api_mode"]
532 + == "chat"
533 + )
534 +
535 + for provider in ("codex_oauth", "github_copilot_oauth", "xai_grok_oauth"):
536 + assert "a0_api_mode" not in oauth_provider_config["chat"][provider]["kwargs"]
537 +
538 +
539 def test_missing_api_key_banner_does_not_include_auto_modal_metadata(monkeypatch):
540 from plugins._model_config.helpers import model_config
541