diff --git a/README.md b/README.md index 79f6403eb6..cd6bb04c1f 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,13 @@ streams simulate chunks from a non-streaming response, while no-tool streams sta api_key: $OPPER_API_KEY base_url: https://api.opper.ai/v3/compat + - name: api-route-gpt-6.1-sol + display_name: GPT 6.1 Sol (API Route) + use: langchain_openai:ChatOpenAI + model: gpt-6.1-sol + api_key: $API_ROUTE_API_KEY + base_url: https://global.api-route.com/v1 + - name: gpt-5-responses display_name: GPT-5 (Responses API) use: langchain_openai:ChatOpenAI @@ -351,6 +358,8 @@ streams simulate chunks from a non-streaming response, while no-tool streams sta OpenRouter and similar OpenAI-compatible gateways should be configured with `langchain_openai:ChatOpenAI` plus `base_url`. If you prefer a provider-specific environment variable name, point `api_key` at that variable explicitly (for example `api_key: $OPENROUTER_API_KEY`). + [API Route](https://www.api-route.com) is also available in the setup wizard. It saves your key as `API_ROUTE_API_KEY` and uses the Chat Completions endpoint above. Model availability depends on your key's group and permissions; check the authenticated `GET https://global.api-route.com/v1/models` catalog before replacing the model in `config.yaml`, and use its returned ID unchanged without an upstream provider prefix. + The `write_file` tool's output-budget hint uses the active model's effective `max_tokens`. Missing or unusable limits, including YAML `.inf`, `-.inf`, `.nan`, and values too large for the character estimate, omit this hint without failing tool assembly; provider-specific model validation still applies. To route OpenAI models through `/v1/responses`, keep using `langchain_openai:ChatOpenAI` and set `use_responses_api: true` with `output_version: responses/v1`. diff --git a/README_zh.md b/README_zh.md index 2fce7a4d0d..d090bc01be 100644 --- a/README_zh.md +++ b/README_zh.md @@ -179,6 +179,13 @@ YAML 同名模型优先,已有任务保留原配置快照。托管模型使用 api_key: $OPPER_API_KEY base_url: https://api.opper.ai/v3/compat + - name: api-route-gpt-6.1-sol + display_name: GPT 6.1 Sol (API Route) + use: langchain_openai:ChatOpenAI + model: gpt-6.1-sol + api_key: $API_ROUTE_API_KEY + base_url: https://global.api-route.com/v1 + - name: gpt-5-responses display_name: GPT-5 (Responses API) use: langchain_openai:ChatOpenAI @@ -202,6 +209,8 @@ YAML 同名模型优先,已有任务保留原配置快照。托管模型使用 OpenRouter 以及类似的 OpenAI 兼容网关,建议通过 `langchain_openai:ChatOpenAI` 配合 `base_url` 来配置。如果你更想用 provider 自己的环境变量名,也可以直接把 `api_key` 指向对应变量,例如 `api_key: $OPENROUTER_API_KEY`。 + Setup Wizard 也支持 [API Route](https://www.api-route.com),会将密钥保存为 `API_ROUTE_API_KEY`,并使用上面的 Chat Completions 端点。可用模型取决于密钥所属组别和权限;修改 `config.yaml` 中的模型前,请先查询需要认证的 `GET https://global.api-route.com/v1/models` 模型目录,并原样使用返回的模型 ID,不要添加上游 provider 前缀。 + 如果要让 OpenAI 模型走 `/v1/responses`,继续使用 `langchain_openai:ChatOpenAI`,并设置 `use_responses_api: true` 和 `output_version: responses/v1`。 如果某个模型的 provider 约定与 DeerFlow 通用的 thinking/effort 假设不同,可以为该模型声明 `reasoning:` 块(thinking 为 `unsupported`/`optional`/`required`、允许的 effort 取值及别名和默认值、payload 方言、推理历史要求)。Setup Wizard 内置的 Z.AI GLM-5.3-Flash 配置就使用了它:前台和后台调用都会保持 thinking 开启,effort 选择器只提供该模型自己的 `low`/`high`/`max` 档位。未声明该块的配置行为保持不变。具体格式与等价的手动配置见 `config.example.yaml`。 diff --git a/backend/tests/test_api_route_setup_wizard.py b/backend/tests/test_api_route_setup_wizard.py new file mode 100644 index 0000000000..b486e9d840 --- /dev/null +++ b/backend/tests/test_api_route_setup_wizard.py @@ -0,0 +1,57 @@ +"""API Route setup uses the existing OpenAI-compatible wizard path.""" + +import yaml +from wizard.providers import LLM_PROVIDERS +from wizard.steps import llm as llm_step +from wizard.writer import build_minimal_config + + +def api_route_provider(): + provider = next((p for p in LLM_PROVIDERS if p.name == "api_route"), None) + assert provider is not None + return provider + + +def test_api_route_uses_versioned_chat_endpoint_and_bare_model_id(): + provider = api_route_provider() + assert provider.use == "langchain_openai:ChatOpenAI" + assert provider.package == "langchain-openai" + assert provider.env_var == "API_ROUTE_API_KEY" + assert provider.models == ["gpt-6.1-sol"] + assert provider.default_model == "gpt-6.1-sol" + assert provider.extra_config["base_url"] == "https://global.api-route.com/v1" + + +def test_api_route_generated_config_preserves_key_reference_and_model(): + provider = api_route_provider() + config = yaml.safe_load( + build_minimal_config( + provider_use=provider.use, + model_name=provider.default_model, + display_name=provider.display_name, + api_key_field=provider.api_key_field, + env_var=provider.env_var, + extra_model_config=provider.extra_config_for(provider.default_model), + ) + ) + model = config["models"][0] + assert model["model"] == "gpt-6.1-sol" + assert model["api_key"] == "$API_ROUTE_API_KEY" + assert model["base_url"] == "https://global.api-route.com/v1" + assert model["use"] == "langchain_openai:ChatOpenAI" + assert model["temperature"] == 0.7 + assert "use_responses_api" not in model + assert not model.get("supports_vision", False) + assert not model.get("supports_thinking", False) + + +def test_api_route_wizard_selects_preset_and_collects_key(monkeypatch): + provider = api_route_provider() + monkeypatch.setattr(llm_step, "LLM_PROVIDERS", [provider]) + monkeypatch.setattr(llm_step, "ask_choice", lambda *_args, **_kwargs: 0) + monkeypatch.setattr(llm_step, "ask_secret", lambda prompt: "test-api-route-key" if prompt == "API_ROUTE_API_KEY" else None) + result = llm_step.run_llm_step() + assert result.model_name == "gpt-6.1-sol" + assert result.provider.extra_config["base_url"] == "https://global.api-route.com/v1" + assert result.provider.env_var == "API_ROUTE_API_KEY" + assert result.api_key == "test-api-route-key" diff --git a/scripts/wizard/providers.py b/scripts/wizard/providers.py index a2ba692ea3..968e072854 100644 --- a/scripts/wizard/providers.py +++ b/scripts/wizard/providers.py @@ -512,6 +512,23 @@ LLM_PROVIDERS: list[LLMProvider] = [ "temperature": 0.7, }, ), + LLMProvider( + name="api_route", + display_name="API Route", + description="OpenAI-compatible gateway (models depend on your API key)", + use="langchain_openai:ChatOpenAI", + models=["gpt-6.1-sol"], + default_model="gpt-6.1-sol", + env_var="API_ROUTE_API_KEY", + package="langchain-openai", + extra_config={ + "base_url": "https://global.api-route.com/v1", + "request_timeout": 600.0, + "max_retries": 2, + "max_tokens": 8192, + "temperature": 0.7, + }, + ), LLMProvider( name="vllm", display_name="vLLM",