mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
fix(models): refresh bundled provider catalogs (#109410)
* fix(models): refresh bundled provider catalogs * docs(models): refresh generated docs map * fix(xiaomi): keep provider helper private * chore(release): defer catalog release note
This commit is contained in:
+1
-1
@@ -182,7 +182,7 @@ Notes:
|
||||
```bash
|
||||
openclaw infer image providers --json
|
||||
openclaw infer image generate \
|
||||
--model google/gemini-3.1-flash-image-preview \
|
||||
--model google/gemini-3.1-flash-image \
|
||||
--prompt "Minimal flat test image: one blue square on a white background, no text." \
|
||||
--output ./openclaw-infer-image-smoke.png \
|
||||
--json
|
||||
|
||||
@@ -300,37 +300,36 @@ messages and normalizes `stats.cached` into `cacheRead`; legacy
|
||||
|
||||
### Other bundled provider plugins
|
||||
|
||||
| Provider | Id | Auth env | Example model |
|
||||
| --------------------------------------- | -------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| Arcee | `arcee` | `ARCEEAI_API_KEY` or `OPENROUTER_API_KEY` | `arcee/trinity-large-thinking` |
|
||||
| BytePlus | `byteplus` / `byteplus-plan` | `BYTEPLUS_API_KEY` | `byteplus-plan/ark-code-latest` |
|
||||
| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | `cerebras/zai-glm-4.7` |
|
||||
| Chutes | `chutes` | `CHUTES_API_KEY` or `CHUTES_OAUTH_TOKEN` | `chutes/zai-org/GLM-4.7-TEE` |
|
||||
| ClawRouter | `clawrouter` | `CLAWROUTER_API_KEY` | `clawrouter/anthropic/claude-sonnet-4-6` |
|
||||
| Cohere | `cohere` | `COHERE_API_KEY` | `cohere/command-a-plus-05-2026` |
|
||||
| DeepInfra | `deepinfra` | `DEEPINFRA_API_KEY` | `deepinfra/deepseek-ai/DeepSeek-V4-Flash` |
|
||||
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
|
||||
| Featherless AI | `featherless` | `FEATHERLESS_API_KEY` | `featherless/Qwen/Qwen3-32B` |
|
||||
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | - |
|
||||
| GMI Cloud | `gmi` | `GMI_API_KEY` | `gmi/google/gemini-3.1-flash-lite` |
|
||||
| Groq | `groq` | `GROQ_API_KEY` | `groq/llama-3.3-70b-versatile` |
|
||||
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
|
||||
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M3` |
|
||||
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
|
||||
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
|
||||
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-ultra-550b-a55b` |
|
||||
| NovitaAI | `novita` | `NOVITA_API_KEY` | `novita/deepseek/deepseek-v3-0324` |
|
||||
| [Ollama Cloud](/providers/ollama-cloud) | `ollama-cloud` | `OLLAMA_API_KEY` | `ollama-cloud/kimi-k2.6` |
|
||||
| OpenRouter | `openrouter` | OpenRouter OAuth or `OPENROUTER_API_KEY` | `openrouter/auto` |
|
||||
| Qianfan | `qianfan` | `QIANFAN_API_KEY` | `qianfan/deepseek-v3.2` |
|
||||
| [Qwen OAuth](/providers/qwen-oauth) | `qwen-oauth` | `QWEN_API_KEY` | `qwen-oauth/qwen3.5-plus` |
|
||||
| Tencent TokenHub | `tencent-tokenhub` | `TOKENHUB_API_KEY` | `tencent-tokenhub/hy3-preview` |
|
||||
| Together | `together` | `TOGETHER_API_KEY` | `together/meta-llama/Llama-3.3-70B-Instruct-Turbo` |
|
||||
| Venice | `venice` | `VENICE_API_KEY` | - |
|
||||
| Vercel AI Gateway | `vercel-ai-gateway` | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway/anthropic/claude-opus-4.6` |
|
||||
| Volcano Engine (Doubao) | `volcengine` / `volcengine-plan` | `VOLCANO_ENGINE_API_KEY` | `volcengine-plan/ark-code-latest` |
|
||||
| xAI | `xai` | SuperGrok/X Premium OAuth or `XAI_API_KEY` | `xai/grok-4.3` |
|
||||
| Xiaomi | `xiaomi` / `xiaomi-token-plan` | `XIAOMI_API_KEY` / `XIAOMI_TOKEN_PLAN_API_KEY` | `xiaomi/mimo-v2-flash` / `xiaomi-token-plan/mimo-v2.5-pro` |
|
||||
| Provider | Id | Auth env | Example model |
|
||||
| --------------------------------------- | -------------------------------- | ---------------------------------------------------- | ------------------------------------------------------ |
|
||||
| Arcee | `arcee` | `ARCEEAI_API_KEY` or `OPENROUTER_API_KEY` | `arcee/trinity-large-thinking` |
|
||||
| BytePlus | `byteplus` / `byteplus-plan` | `BYTEPLUS_API_KEY` | `byteplus-plan/ark-code-latest` |
|
||||
| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | `cerebras/zai-glm-4.7` |
|
||||
| Chutes | `chutes` | `CHUTES_API_KEY` or `CHUTES_OAUTH_TOKEN` | `chutes/zai-org/GLM-5-TEE` |
|
||||
| ClawRouter | `clawrouter` | `CLAWROUTER_API_KEY` | `clawrouter/anthropic/claude-sonnet-4-6` |
|
||||
| Cohere | `cohere` | `COHERE_API_KEY` | `cohere/command-a-plus-05-2026` |
|
||||
| DeepInfra | `deepinfra` | `DEEPINFRA_API_KEY` | `deepinfra/deepseek-ai/DeepSeek-V4-Flash` |
|
||||
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
|
||||
| Featherless AI | `featherless` | `FEATHERLESS_API_KEY` | `featherless/Qwen/Qwen3-32B` |
|
||||
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | - |
|
||||
| GMI Cloud | `gmi` | `GMI_API_KEY` | `gmi/google/gemini-3.1-flash-lite` |
|
||||
| Groq | `groq` | `GROQ_API_KEY` | `groq/llama-3.3-70b-versatile` |
|
||||
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
|
||||
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M3` |
|
||||
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
|
||||
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
|
||||
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-ultra-550b-a55b` |
|
||||
| NovitaAI | `novita` | `NOVITA_API_KEY` | `novita/deepseek/deepseek-v3-0324` |
|
||||
| [Ollama Cloud](/providers/ollama-cloud) | `ollama-cloud` | `OLLAMA_API_KEY` | `ollama-cloud/kimi-k2.6` |
|
||||
| OpenRouter | `openrouter` | OpenRouter OAuth or `OPENROUTER_API_KEY` | `openrouter/auto` |
|
||||
| Qianfan | `qianfan` | `QIANFAN_API_KEY` | `qianfan/deepseek-v3.2` |
|
||||
| Tencent TokenHub | `tencent-tokenhub` | `TOKENHUB_API_KEY` | `tencent-tokenhub/hy3-preview` |
|
||||
| Together | `together` | `TOGETHER_API_KEY` | `together/meta-llama/Llama-3.3-70B-Instruct-Turbo` |
|
||||
| Venice | `venice` | `VENICE_API_KEY` | - |
|
||||
| Vercel AI Gateway | `vercel-ai-gateway` | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway/anthropic/claude-opus-4.6` |
|
||||
| Volcano Engine (Doubao) | `volcengine` / `volcengine-plan` | `VOLCANO_ENGINE_API_KEY` | `volcengine-plan/ark-code-latest` |
|
||||
| xAI | `xai` | SuperGrok/X Premium OAuth or `XAI_API_KEY` | `xai/grok-4.3` |
|
||||
| Xiaomi | `xiaomi` / `xiaomi-token-plan` | `XIAOMI_API_KEY` / `XIAOMI_TOKEN_PLAN_API_KEY` | `xiaomi/mimo-v2.5` / `xiaomi-token-plan/mimo-v2.5-pro` |
|
||||
|
||||
#### Quirks worth knowing
|
||||
|
||||
@@ -339,13 +338,13 @@ messages and normalizes `stats.cached` into `cacheRead`; legacy
|
||||
Applies its app-attribution headers and Anthropic `cache_control` markers only on verified `openrouter.ai` routes. DeepSeek, Moonshot, and ZAI refs are cache-TTL eligible for OpenRouter-managed prompt caching but do not receive Anthropic cache markers. As a proxy-style OpenAI-compatible path, it skips native-OpenAI-only shaping (`serviceTier`, Responses `store`, prompt-cache hints, OpenAI reasoning-compat). Gemini-backed refs keep proxy-Gemini thought-signature sanitation only.
|
||||
</Accordion>
|
||||
<Accordion title="Kilo Gateway">
|
||||
Gemini-backed refs follow the same proxy-Gemini sanitation path; `kilocode/kilo/auto` and other proxy-reasoning-unsupported refs skip proxy reasoning injection.
|
||||
Gemini-backed refs follow the same proxy-Gemini sanitation path; `kilocode/kilo-auto/balanced` and other proxy-reasoning-unsupported refs skip proxy reasoning injection.
|
||||
</Accordion>
|
||||
<Accordion title="MiniMax">
|
||||
API-key onboarding writes explicit M3 and M2.7 chat model definitions; image understanding stays on the plugin-owned `MiniMax-VL-01` media provider.
|
||||
</Accordion>
|
||||
<Accordion title="NVIDIA">
|
||||
Model ids use a `nvidia/<vendor>/<model>` namespace (for example `nvidia/nvidia/nemotron-...` alongside `nvidia/moonshotai/kimi-k2.5`); pickers preserve the literal `<provider>/<model-id>` composition while the canonical key sent to the API stays single-prefixed.
|
||||
Model ids use a `nvidia/<vendor>/<model>` namespace (for example `nvidia/nvidia/nemotron-...`); pickers preserve the literal `<provider>/<model-id>` composition while the canonical key sent to the API stays single-prefixed.
|
||||
</Accordion>
|
||||
<Accordion title="xAI">
|
||||
Uses the xAI Responses path. The recommended path is SuperGrok/X Premium OAuth; API keys still work via `XAI_API_KEY` or plugin config, and Grok `web_search` reuses the same auth profile before API-key fallback. Grok 4.5 is selectable for chat, coding, and agentic work where available; `grok-4.3` remains the regional-safe bundled default. Older `/fast` and `params.fastMode: true` configurations still resolve through xAI's Grok 4.3 compatibility redirects, but new configurations should select a current model directly. `tool_stream` defaults on; disable via `agents.defaults.models["xai/<model>"].params.tool_stream=false`.
|
||||
@@ -378,10 +377,8 @@ Kimi model IDs:
|
||||
- `moonshot/kimi-k2.6`
|
||||
- `moonshot/kimi-k3`
|
||||
- `moonshot/kimi-k2.7-code`
|
||||
- `moonshot/kimi-k2.7-code-highspeed`
|
||||
- `moonshot/kimi-k2.5`
|
||||
- `moonshot/kimi-k2-thinking`
|
||||
- `moonshot/kimi-k2-thinking-turbo`
|
||||
- `moonshot/kimi-k2-turbo`
|
||||
|
||||
[//]: # "moonshot-kimi-k2-model-refs:end"
|
||||
|
||||
@@ -412,8 +409,9 @@ Kimi Coding uses Moonshot AI's Anthropic-compatible endpoint:
|
||||
|
||||
- Provider: `kimi`
|
||||
- Auth: `KIMI_API_KEY`
|
||||
- Kimi K3: `kimi/k3` (256K) or `kimi/k3[1m]` (1M, Allegretto and above)
|
||||
- Kimi K2.7 Code: `kimi/kimi-for-coding`
|
||||
- Kimi K3: `kimi/k3` (256K) or `kimi/k3[1m]` (1M plan)
|
||||
- Kimi Code: `kimi/kimi-for-coding`
|
||||
- Kimi Code HighSpeed: `kimi/kimi-for-coding-highspeed`
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -459,9 +457,6 @@ In onboarding/configure model pickers, the Volcengine auth choice prefers both `
|
||||
<Tab title="Coding models (volcengine-plan)">
|
||||
- `volcengine-plan/ark-code-latest`
|
||||
- `volcengine-plan/doubao-seed-code`
|
||||
- `volcengine-plan/kimi-k2.5`
|
||||
- `volcengine-plan/kimi-k2-thinking`
|
||||
- `volcengine-plan/glm-4.7`
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@@ -496,9 +491,7 @@ In onboarding/configure model pickers, the BytePlus auth choice prefers both `by
|
||||
</Tab>
|
||||
<Tab title="Coding models (byteplus-plan)">
|
||||
- `byteplus-plan/ark-code-latest`
|
||||
- `byteplus-plan/doubao-seed-code`
|
||||
- `byteplus-plan/kimi-k2.5`
|
||||
- `byteplus-plan/kimi-k2-thinking`
|
||||
- `byteplus-plan/glm-4.7`
|
||||
|
||||
</Tab>
|
||||
@@ -510,13 +503,13 @@ Synthetic provides Anthropic-compatible models behind the `synthetic` provider:
|
||||
|
||||
- Provider: `synthetic`
|
||||
- Auth: `SYNTHETIC_API_KEY`
|
||||
- Example model: `synthetic/hf:MiniMaxAI/MiniMax-M2.5`
|
||||
- Example model: `synthetic/hf:MiniMaxAI/MiniMax-M3`
|
||||
- CLI: `openclaw onboard --auth-choice synthetic-api-key`
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: { model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M2.5" } },
|
||||
defaults: { model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M3" } },
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
@@ -525,7 +518,7 @@ Synthetic provides Anthropic-compatible models behind the `synthetic` provider:
|
||||
baseUrl: "https://api.synthetic.new/anthropic",
|
||||
apiKey: "${SYNTHETIC_API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [{ id: "hf:MiniMaxAI/MiniMax-M2.5", name: "MiniMax M2.5" }],
|
||||
models: [{ id: "hf:MiniMaxAI/MiniMax-M3", name: "MiniMax M3" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1527,7 +1527,6 @@
|
||||
"providers/pixverse",
|
||||
"providers/qianfan",
|
||||
"providers/qwen",
|
||||
"providers/qwen-oauth",
|
||||
"providers/runway",
|
||||
"providers/senseaudio",
|
||||
"providers/sglang",
|
||||
|
||||
+3
-14
@@ -7663,7 +7663,8 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
||||
- H2: Install plugin
|
||||
- H2: Getting started
|
||||
- H2: Non-interactive setup
|
||||
- H2: Built-in catalog
|
||||
- H2: Direct Arcee catalog
|
||||
- H2: OpenRouter catalog
|
||||
- H2: Supported features
|
||||
- H2: Related
|
||||
|
||||
@@ -8242,18 +8243,6 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
||||
- H2: Config example
|
||||
- H2: Related
|
||||
|
||||
## providers/qwen-oauth.md
|
||||
|
||||
- Route: /providers/qwen-oauth
|
||||
- Headings:
|
||||
- H2: Setup
|
||||
- H2: Defaults
|
||||
- H2: How this differs from Qwen
|
||||
- H2: Models
|
||||
- H2: Migration
|
||||
- H2: Troubleshooting
|
||||
- H2: Related
|
||||
|
||||
## providers/qwen.md
|
||||
|
||||
- Route: /providers/qwen
|
||||
@@ -8343,7 +8332,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
||||
- H2: Privacy modes
|
||||
- H2: Getting started
|
||||
- H2: Model selection
|
||||
- H2: Built-in catalog (38 models)
|
||||
- H2: Built-in catalog (30 models)
|
||||
- H2: Model discovery
|
||||
- H2: DeepSeek V4 replay behavior
|
||||
- H2: Streaming and tool support
|
||||
|
||||
@@ -371,7 +371,7 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
},
|
||||
imageGenerationModel: {
|
||||
primary: "openai/gpt-image-2",
|
||||
fallbacks: ["google/gemini-3.1-flash-image-preview"],
|
||||
fallbacks: ["google/gemini-3.1-flash-image"],
|
||||
},
|
||||
videoGenerationModel: {
|
||||
primary: "qwen/wan2.6-t2v",
|
||||
@@ -408,7 +408,7 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
- Prefer explicit `provider/model` refs. Bare IDs are accepted for compatibility; if a bare ID uniquely matches a configured image-capable entry in `models.providers.*.models`, OpenClaw qualifies it to that provider. Ambiguous configured matches require an explicit provider prefix.
|
||||
- `imageGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
||||
- Used by the shared image-generation capability and any future tool/plugin surface that generates images.
|
||||
- Typical values: `google/gemini-3.1-flash-image-preview` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, `openai/gpt-image-2` for OpenAI Images, or `openai/gpt-image-1.5` for transparent-background OpenAI PNG/WebP output.
|
||||
- Typical values: `google/gemini-3.1-flash-image` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, `openai/gpt-image-2` for OpenAI Images, or `openai/gpt-image-1.5` for transparent-background OpenAI PNG/WebP output.
|
||||
- If you select a provider/model directly, configure matching provider auth too (for example `GEMINI_API_KEY` or `GOOGLE_API_KEY` for `google/*`, `OPENAI_API_KEY` or OpenAI Codex OAuth for `openai/gpt-image-2` / `openai/gpt-image-1.5`, `FAL_KEY` for `fal/*`).
|
||||
- If omitted, `image_generate` can still infer an auth-backed provider default. It tries the current default provider first, then the remaining registered image-generation providers in provider-id order.
|
||||
- `musicGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
||||
|
||||
@@ -774,8 +774,8 @@ Interactive custom-provider onboarding infers image input for known vision-model
|
||||
env: { SYNTHETIC_API_KEY: "sk-..." },
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M2.5" },
|
||||
models: { "synthetic/hf:MiniMaxAI/MiniMax-M2.5": { alias: "MiniMax M2.5" } },
|
||||
model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M3" },
|
||||
models: { "synthetic/hf:MiniMaxAI/MiniMax-M3": { alias: "MiniMax M3" } },
|
||||
},
|
||||
},
|
||||
models: {
|
||||
@@ -787,12 +787,12 @@ Interactive custom-provider onboarding infers image input for known vision-model
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "hf:MiniMaxAI/MiniMax-M2.5",
|
||||
name: "MiniMax M2.5",
|
||||
id: "hf:MiniMaxAI/MiniMax-M3",
|
||||
name: "MiniMax M3",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 192000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -560,7 +560,7 @@ Docker runners below with an explicit `OPENCLAW_PROFILE_FILE`.
|
||||
- Optional narrowing:
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS="openai,google,openrouter,xai"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS="deepinfra"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-2,google/gemini-3.1-flash-image-preview,openrouter/google/gemini-3.1-flash-image-preview,xai/grok-imagine-image"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-2,google/gemini-3.1-flash-image,openrouter/google/gemini-3.1-flash-image-preview,xai/grok-imagine-image"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_CASES="google:flash-generate,google:pro-edit,openrouter:generate,xai:default-generate,xai:default-edit"`
|
||||
- Optional auth behavior:
|
||||
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to force profile-store auth and ignore env-only overrides
|
||||
@@ -572,7 +572,7 @@ test passes:
|
||||
OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_INFER_CLI_TEST=1 pnpm test:live -- test/image-generation.infer-cli.live.test.ts
|
||||
openclaw infer image providers --json
|
||||
openclaw infer image generate \
|
||||
--model google/gemini-3.1-flash-image-preview \
|
||||
--model google/gemini-3.1-flash-image \
|
||||
--prompt "Minimal flat test image: one blue square on a white background, no text." \
|
||||
--output ./openclaw-infer-image-smoke.png \
|
||||
--json
|
||||
|
||||
@@ -297,7 +297,7 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
- **[qqbot](/plugins/reference/qqbot)** (`@openclaw/qqbot`) - npm; ClawHub. OpenClaw QQ Bot channel plugin for group and direct-message workflows.
|
||||
|
||||
- **[qwen](/plugins/reference/qwen)** (`@openclaw/qwen-provider`) - npm; ClawHub: `clawhub:@openclaw/qwen-provider`. Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw.
|
||||
- **[qwen](/plugins/reference/qwen)** (`@openclaw/qwen-provider`) - npm; ClawHub: `clawhub:@openclaw/qwen-provider`. Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw.
|
||||
|
||||
- **[raft](/plugins/reference/raft)** (`@openclaw/raft`) - npm; ClawHub. OpenClaw Raft channel plugin for secure CLI wake bridges.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
summary: "Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw."
|
||||
summary: "Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw."
|
||||
read_when:
|
||||
- You are installing, configuring, or auditing the qwen plugin
|
||||
title: "Qwen plugin"
|
||||
@@ -7,7 +7,7 @@ title: "Qwen plugin"
|
||||
|
||||
# Qwen plugin
|
||||
|
||||
Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw.
|
||||
Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Token Plan, Bailian Token Plan model provider support to OpenClaw.
|
||||
|
||||
## Distribution
|
||||
|
||||
@@ -16,9 +16,8 @@ Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CL
|
||||
|
||||
## Surface
|
||||
|
||||
providers: `qwen`, `qwencloud`, `modelstudio`, `dashscope`, `qwen-oauth`, `qwen-portal`, `qwen-cli`, `qwen-token-plan`, `bailian-token-plan`; contracts: `mediaUnderstandingProviders`, `videoGenerationProviders`
|
||||
providers: `qwen`, `qwencloud`, `modelstudio`, `dashscope`, `qwen-token-plan`, `bailian-token-plan`; contracts: `mediaUnderstandingProviders`, `videoGenerationProviders`
|
||||
|
||||
## Related docs
|
||||
|
||||
- [qwen](/providers/qwen)
|
||||
- [qwen-oauth](/providers/qwen-oauth)
|
||||
|
||||
@@ -505,7 +505,7 @@ catalog, API-key auth, and dynamic model resolution.
|
||||
| Family | What it wires in | Bundled examples |
|
||||
| --- | --- | --- |
|
||||
| `google-thinking` | Gemini thinking payload normalization on the shared stream path | `google`, `google-gemini-cli` |
|
||||
| `kilocode-thinking` | Kilo reasoning wrapper on the shared proxy stream path, with `kilo/auto` and unsupported proxy reasoning ids skipping injected thinking | `kilocode` |
|
||||
| `kilocode-thinking` | Kilo reasoning wrapper on the shared proxy stream path, with `kilo-auto/balanced` and unsupported proxy reasoning ids skipping injected thinking | `kilocode` |
|
||||
| `moonshot-thinking` | Moonshot binary native-thinking payload mapping from config + `/think` level | `moonshot` |
|
||||
| `minimax-fast-mode` | MiniMax fast-mode model rewrite on the shared stream path | `minimax`, `minimax-portal` |
|
||||
| `openai-responses-defaults` | Shared native OpenAI/Codex Responses wrappers: attribution headers, `/fast`/`serviceTier`, text verbosity, native Codex web search, reasoning-compat payload shaping, and Responses context management | `openai` |
|
||||
|
||||
@@ -101,7 +101,7 @@ openclaw gateway restart
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Built-in catalog
|
||||
## Direct Arcee catalog
|
||||
|
||||
| Model ref | Name | Input | Context | Max output | Cost (in/out per 1M) | Tools | Notes |
|
||||
| ------------------------------ | ---------------------- | ----- | ------- | ---------- | -------------------- | ----- | ----------------------------------------- |
|
||||
@@ -113,6 +113,10 @@ openclaw gateway restart
|
||||
The onboarding preset sets `arcee/trinity-large-thinking` as the default model.
|
||||
</Tip>
|
||||
|
||||
## OpenRouter catalog
|
||||
|
||||
OpenRouter onboarding exposes `arcee/trinity-large-preview` and `arcee/trinity-large-thinking`. OpenClaw keeps those provider-qualified model refs in config and sends OpenRouter's canonical `arcee-ai/*` runtime ids. Trinity Mini is no longer served by OpenRouter; use the direct Arcee API for that model.
|
||||
|
||||
## Supported features
|
||||
|
||||
| Feature | Supported |
|
||||
@@ -130,8 +134,9 @@ The onboarding preset sets `arcee/trinity-large-thinking` as the default model.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="OpenRouter routing">
|
||||
When using Arcee models via OpenRouter, the same `arcee/*` model refs apply.
|
||||
OpenClaw routes transparently based on your auth choice. See the
|
||||
OpenRouter uses the same `arcee/trinity-large-thinking` OpenClaw model ref.
|
||||
OpenClaw routes it with the canonical `arcee-ai/trinity-large-thinking`
|
||||
OpenRouter runtime id. See the
|
||||
[OpenRouter provider docs](/providers/openrouter) for OpenRouter-specific
|
||||
configuration details.
|
||||
</Accordion>
|
||||
|
||||
@@ -51,7 +51,7 @@ Choose your preferred auth method and follow the setup steps.
|
||||
auth: "aws-sdk",
|
||||
models: [
|
||||
{
|
||||
id: "us.anthropic.claude-opus-4-6-v1:0",
|
||||
id: "us.anthropic.claude-opus-4-6-v1",
|
||||
name: "Claude Opus 4.6 (Bedrock)",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
@@ -65,7 +65,7 @@ Choose your preferred auth method and follow the setup steps.
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "amazon-bedrock/us.anthropic.claude-opus-4-6-v1:0" },
|
||||
model: { primary: "amazon-bedrock/us.anthropic.claude-opus-4-6-v1" },
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -262,8 +262,8 @@ openclaw models list
|
||||
first in `openclaw models list` since they generally offer better capacity
|
||||
and automatic failover.
|
||||
|
||||
Inference profile IDs look like `us.anthropic.claude-opus-4-6-v1:0` (regional)
|
||||
or `anthropic.claude-opus-4-6-v1:0` (global). If the backing model is already
|
||||
Inference profile IDs look like `us.anthropic.claude-opus-4-6-v1` (regional)
|
||||
or `anthropic.claude-opus-4-6-v1` (global). If the backing model is already
|
||||
in the discovery results, the profile inherits its full capability set;
|
||||
otherwise safe defaults apply.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ read_when:
|
||||
- You need the Cerebras API key env var or CLI auth choice
|
||||
---
|
||||
|
||||
[Cerebras](https://www.cerebras.ai) provides high-speed OpenAI-compatible inference on custom inference hardware. The plugin ships a static four-model catalog (no live discovery).
|
||||
[Cerebras](https://www.cerebras.ai) provides high-speed OpenAI-compatible inference on custom inference hardware. The plugin ships a static two-model catalog (no live discovery).
|
||||
|
||||
| Property | Value |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
@@ -57,7 +57,7 @@ export CEREBRAS_API_KEY=csk-...
|
||||
openclaw models list --provider cerebras
|
||||
```
|
||||
|
||||
Lists all four static models. If `CEREBRAS_API_KEY` is unresolved, `openclaw models status --json` reports the missing credential under `auth.unusableProfiles`.
|
||||
Lists both static models. If `CEREBRAS_API_KEY` is unresolved, `openclaw models status --json` reports the missing credential under `auth.unusableProfiles`.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -73,18 +73,12 @@ openclaw onboard --non-interactive \
|
||||
|
||||
## Built-in catalog
|
||||
|
||||
All four models share a 128k context window and 8,192 max output tokens.
|
||||
Both models share a 128k context window and 8,192 max output tokens.
|
||||
|
||||
| Model ref | Name | Reasoning | Notes |
|
||||
| ----------------------------------------- | -------------------- | --------- | -------------------------------------- |
|
||||
| `cerebras/zai-glm-4.7` | Z.ai GLM 4.7 | yes | Default model; preview reasoning model |
|
||||
| `cerebras/gpt-oss-120b` | GPT OSS 120B | yes | Production reasoning model |
|
||||
| `cerebras/qwen-3-235b-a22b-instruct-2507` | Qwen 3 235B Instruct | no | Preview non-reasoning model |
|
||||
| `cerebras/llama3.1-8b` | Llama 3.1 8B | no | Production speed-focused model |
|
||||
|
||||
<Warning>
|
||||
Cerebras marks `zai-glm-4.7` and `qwen-3-235b-a22b-instruct-2507` as preview models, and `llama3.1-8b` plus `qwen-3-235b-a22b-instruct-2507` are documented for deprecation on May 27, 2026. Check Cerebras' [supported-models page](https://inference-docs.cerebras.ai/models/overview) before relying on them for production workloads.
|
||||
</Warning>
|
||||
| Model ref | Name | Reasoning | Notes |
|
||||
| ----------------------- | ------------ | --------- | -------------------------------------- |
|
||||
| `cerebras/zai-glm-4.7` | Z.ai GLM 4.7 | yes | Default model; preview reasoning model |
|
||||
| `cerebras/gpt-oss-120b` | GPT OSS 120B | yes | Production reasoning model |
|
||||
|
||||
## Manual config
|
||||
|
||||
|
||||
+16
-20
@@ -31,7 +31,7 @@ openclaw gateway restart
|
||||
|
||||
## Getting started
|
||||
|
||||
Both paths set the default model to `chutes/zai-org/GLM-4.7-TEE` and register
|
||||
Both paths set the default model to `chutes/zai-org/GLM-5-TEE` and register
|
||||
the Chutes catalog.
|
||||
|
||||
<Tabs>
|
||||
@@ -74,28 +74,24 @@ static catalog is used automatically.
|
||||
|
||||
## Default aliases
|
||||
|
||||
OpenClaw registers three convenience aliases for the Chutes catalog:
|
||||
OpenClaw registers two convenience aliases for the Chutes catalog:
|
||||
|
||||
| Alias | Target model |
|
||||
| --------------- | ----------------------------------------------------- |
|
||||
| `chutes-fast` | `chutes/zai-org/GLM-4.7-FP8` |
|
||||
| `chutes-pro` | `chutes/deepseek-ai/DeepSeek-V3.2-TEE` |
|
||||
| `chutes-vision` | `chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506` |
|
||||
| Alias | Target model |
|
||||
| --------------- | -------------------------------------- |
|
||||
| `chutes-pro` | `chutes/deepseek-ai/DeepSeek-V3.2-TEE` |
|
||||
| `chutes-vision` | `chutes/moonshotai/Kimi-K2.5-TEE` |
|
||||
|
||||
## Built-in starter catalog
|
||||
|
||||
The bundled fallback catalog has 47 models. A representative sample of current refs:
|
||||
The bundled fallback catalog contains these five currently served models:
|
||||
|
||||
| Model ref |
|
||||
| ----------------------------------------------------- |
|
||||
| `chutes/zai-org/GLM-4.7-TEE` |
|
||||
| `chutes/zai-org/GLM-5-TEE` |
|
||||
| `chutes/deepseek-ai/DeepSeek-V3.2-TEE` |
|
||||
| `chutes/deepseek-ai/DeepSeek-R1-0528-TEE` |
|
||||
| `chutes/moonshotai/Kimi-K2.5-TEE` |
|
||||
| `chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506` |
|
||||
| `chutes/Qwen/Qwen3-Coder-Next-TEE` |
|
||||
| `chutes/openai/gpt-oss-120b-TEE` |
|
||||
| Model ref |
|
||||
| -------------------------------------- |
|
||||
| `chutes/zai-org/GLM-5-TEE` |
|
||||
| `chutes/deepseek-ai/DeepSeek-V3.2-TEE` |
|
||||
| `chutes/moonshotai/Kimi-K2.5-TEE` |
|
||||
| `chutes/MiniMaxAI/MiniMax-M2.5-TEE` |
|
||||
| `chutes/Qwen/Qwen3.5-397B-A17B-TEE` |
|
||||
|
||||
Run `openclaw models list --all --provider chutes` for the full list.
|
||||
|
||||
@@ -105,9 +101,9 @@ Run `openclaw models list --all --provider chutes` for the full list.
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "chutes/zai-org/GLM-4.7-TEE" },
|
||||
model: { primary: "chutes/zai-org/GLM-5-TEE" },
|
||||
models: {
|
||||
"chutes/zai-org/GLM-4.7-TEE": { alias: "Chutes GLM 4.7" },
|
||||
"chutes/zai-org/GLM-5-TEE": { alias: "Chutes GLM 5" },
|
||||
"chutes/deepseek-ai/DeepSeek-V3.2-TEE": { alias: "Chutes DeepSeek V3.2" },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,8 +18,8 @@ read_when:
|
||||
| Direct CLI flag | `--fireworks-api-key <key>` |
|
||||
| API | OpenAI-compatible (`openai-completions`) |
|
||||
| Base URL | `https://api.fireworks.ai/inference/v1` |
|
||||
| Default model | `fireworks/accounts/fireworks/routers/kimi-k2p5-turbo` |
|
||||
| Default alias | `Kimi K2.5 Turbo` |
|
||||
| Default model | `fireworks/accounts/fireworks/routers/kimi-k2p6-turbo` |
|
||||
| Default alias | `Kimi K2.6 Turbo` |
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -48,7 +48,7 @@ export FIREWORKS_API_KEY=fw-...
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Onboarding stores the key against the `fireworks` provider in your auth profiles and sets the **Fire Pass** Kimi K2.5 Turbo router as the default model.
|
||||
Onboarding stores the key against the `fireworks` provider in your auth profiles and sets the **Fire Pass** Kimi K2.6 Turbo router as the default model.
|
||||
|
||||
</Step>
|
||||
<Step title="Verify the model is available">
|
||||
@@ -56,7 +56,7 @@ export FIREWORKS_API_KEY=fw-...
|
||||
openclaw models list --provider fireworks
|
||||
```
|
||||
|
||||
The list should include `Kimi K2.6` and `Kimi K2.5 Turbo (Fire Pass)`. If `FIREWORKS_API_KEY` is unresolved, `openclaw models status --json` reports the missing credential under `auth.unusableProfiles`.
|
||||
The list should include `Kimi K2.6` and `Kimi K2.6 Turbo (Fire Pass)`. If `FIREWORKS_API_KEY` is unresolved, `openclaw models status --json` reports the missing credential under `auth.unusableProfiles`.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -79,7 +79,7 @@ openclaw onboard --non-interactive \
|
||||
| Model ref | Name | Input | Context | Max output | Thinking |
|
||||
| ------------------------------------------------------ | --------------------------- | ------------ | ------- | ---------- | -------------------- |
|
||||
| `fireworks/accounts/fireworks/models/kimi-k2p6` | Kimi K2.6 | text + image | 262,144 | 262,144 | Forced off |
|
||||
| `fireworks/accounts/fireworks/routers/kimi-k2p5-turbo` | Kimi K2.5 Turbo (Fire Pass) | text + image | 256,000 | 256,000 | Forced off (default) |
|
||||
| `fireworks/accounts/fireworks/routers/kimi-k2p6-turbo` | Kimi K2.6 Turbo (Fire Pass) | text + image | 256,000 | 256,000 | Forced off (default) |
|
||||
|
||||
<Note>
|
||||
OpenClaw pins all Fireworks Kimi models to `thinking: off` because Kimi on Fireworks can leak chain-of-thought into the visible reply unless the request explicitly disables thinking. Routing the same model through [Moonshot](/providers/moonshot) directly preserves Kimi reasoning output. See [thinking modes](/tools/thinking) for switching between providers.
|
||||
@@ -105,7 +105,7 @@ OpenClaw accepts any Fireworks model or router id at runtime. Use the exact id s
|
||||
<Accordion title="How model id prefixing works">
|
||||
Every Fireworks model ref in OpenClaw starts with `fireworks/` followed by the exact id or router path from the Fireworks platform. For example:
|
||||
|
||||
- Router model: `fireworks/accounts/fireworks/routers/kimi-k2p5-turbo`
|
||||
- Router model: `fireworks/accounts/fireworks/routers/kimi-k2p6-turbo`
|
||||
- Direct model: `fireworks/accounts/fireworks/models/<model-name>`
|
||||
|
||||
OpenClaw strips the `fireworks/` prefix when constructing the API request and sends the remaining path to the Fireworks endpoint as the OpenAI-compatible `model` field.
|
||||
|
||||
@@ -204,9 +204,9 @@ instead of sending it.
|
||||
## Image generation
|
||||
|
||||
The bundled `google` image-generation provider defaults to
|
||||
`google/gemini-3.1-flash-image-preview`.
|
||||
`google/gemini-3.1-flash-image`.
|
||||
|
||||
- Also supports `google/gemini-3-pro-image-preview`
|
||||
- Also supports `google/gemini-3-pro-image`
|
||||
- Generate: up to 4 images per request
|
||||
- Edit mode: enabled, up to 5 input images
|
||||
- Geometry controls: `size`, `aspectRatio`, and `resolution`
|
||||
@@ -218,7 +218,7 @@ To use Google as the default image provider:
|
||||
agents: {
|
||||
defaults: {
|
||||
imageGenerationModel: {
|
||||
primary: "google/gemini-3.1-flash-image-preview",
|
||||
primary: "google/gemini-3.1-flash-image",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -71,15 +71,14 @@ Sets `huggingface/deepseek-ai/DeepSeek-R1` as the default model.
|
||||
|
||||
Model refs use the form `huggingface/<org>/<model>` (Hub-style IDs). OpenClaw's built-in catalog:
|
||||
|
||||
| Model | Ref (prefix with `huggingface/`) |
|
||||
| ---------------------------- | ----------------------------------------- |
|
||||
| DeepSeek R1 | `deepseek-ai/DeepSeek-R1` |
|
||||
| DeepSeek V3.1 | `deepseek-ai/DeepSeek-V3.1` |
|
||||
| GPT-OSS 120B | `openai/gpt-oss-120b` |
|
||||
| Llama 3.3 70B Instruct Turbo | `meta-llama/Llama-3.3-70B-Instruct-Turbo` |
|
||||
| Model | Ref (prefix with `huggingface/`) |
|
||||
| ------------- | -------------------------------- |
|
||||
| DeepSeek R1 | `deepseek-ai/DeepSeek-R1` |
|
||||
| DeepSeek V3.1 | `deepseek-ai/DeepSeek-V3.1` |
|
||||
| GPT-OSS 120B | `openai/gpt-oss-120b` |
|
||||
|
||||
<Tip>
|
||||
When your token is valid, OpenClaw also discovers any other model from **GET** `https://router.huggingface.co/v1/models` at onboarding time and Gateway startup, so your catalog can include far more than the four models above. You can append `:fastest` or `:cheapest` to any model id; HF's router routes to the matching inference provider. Set your default provider order in [Inference Provider settings](https://hf.co/settings/inference-providers).
|
||||
When your token is valid, OpenClaw also discovers any other model from **GET** `https://router.huggingface.co/v1/models` at onboarding time and Gateway startup, so your catalog can include far more than the three models above. You can append `:fastest` or `:cheapest` to any model id; HF's router routes to the matching inference provider. Set your default provider order in [Inference Provider settings](https://hf.co/settings/inference-providers).
|
||||
</Tip>
|
||||
|
||||
## Advanced configuration
|
||||
@@ -172,21 +171,17 @@ When your token is valid, OpenClaw also discovers any other model from **GET** `
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Config: DeepSeek + Llama + GPT-OSS with aliases">
|
||||
<Accordion title="Config: DeepSeek + GPT-OSS with aliases">
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "huggingface/deepseek-ai/DeepSeek-V3.1",
|
||||
fallbacks: [
|
||||
"huggingface/meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
||||
"huggingface/openai/gpt-oss-120b",
|
||||
],
|
||||
fallbacks: ["huggingface/openai/gpt-oss-120b"],
|
||||
},
|
||||
models: {
|
||||
"huggingface/deepseek-ai/DeepSeek-V3.1": { alias: "DeepSeek V3.1" },
|
||||
"huggingface/meta-llama/Llama-3.3-70B-Instruct-Turbo": { alias: "Llama 3.3 70B Turbo" },
|
||||
"huggingface/openai/gpt-oss-120b": { alias: "GPT-OSS 120B" },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -69,7 +69,6 @@ Looking for chat channel docs (WhatsApp/Telegram/Discord/Slack/Mattermost (plugi
|
||||
- [Perplexity (web search)](/providers/perplexity-provider)
|
||||
- [Qianfan](/providers/qianfan)
|
||||
- [Qwen Cloud](/providers/qwen)
|
||||
- [Qwen OAuth / Portal](/providers/qwen-oauth)
|
||||
- [Runway](/providers/runway)
|
||||
- [SenseAudio](/providers/senseaudio)
|
||||
- [SGLang (local models)](/providers/sglang)
|
||||
|
||||
@@ -49,12 +49,14 @@ openclaw gateway restart
|
||||
|
||||
## Default model and catalog
|
||||
|
||||
The default model is `kilocode/kilo/auto`, a provider-owned smart-routing model. OpenClaw does not
|
||||
publish a task-to-upstream-model mapping for it; routing behind `kilo/auto` is owned by Kilo Gateway.
|
||||
The default model is `kilocode/kilo-auto/balanced`, Kilo Gateway's balanced smart-routing tier.
|
||||
OpenClaw does not publish a task-to-upstream-model mapping for it; routing behind
|
||||
`kilo-auto/balanced` is owned by Kilo Gateway.
|
||||
|
||||
At startup OpenClaw queries `GET https://api.kilo.ai/api/gateway/models` and merges discovered models
|
||||
ahead of a static fallback catalog. The static fallback contains only `kilocode/kilo/auto` (`Kilo Auto`,
|
||||
`input: ["text", "image"]`, `reasoning: true`, `contextWindow: 1000000`, `maxTokens: 128000`).
|
||||
ahead of a static fallback catalog. The static fallback contains only
|
||||
`kilocode/kilo-auto/balanced` (`Auto Balanced`, `input: ["text", "image"]`, `reasoning: true`,
|
||||
`contextWindow: 1000000`, `maxTokens: 65536`).
|
||||
|
||||
Any model on the gateway is addressable as `kilocode/<upstream-id>` (for example
|
||||
`kilocode/anthropic/claude-sonnet-4`, `kilocode/openai/gpt-5.5`). Run `/models kilocode` or
|
||||
@@ -67,7 +69,7 @@ Any model on the gateway is addressable as `kilocode/<upstream-id>` (for example
|
||||
env: { KILOCODE_API_KEY: "<your-kilocode-api-key>" }, // pragma: allowlist secret
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "kilocode/kilo/auto" },
|
||||
model: { primary: "kilocode/kilo-auto/balanced" },
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -92,14 +94,14 @@ Any model on the gateway is addressable as `kilocode/<upstream-id>` (for example
|
||||
models that support it.
|
||||
|
||||
<Warning>
|
||||
`kilocode/kilo/auto` and `x-ai/*` refs skip reasoning-effort injection. Use a concrete model
|
||||
ref such as `kilocode/anthropic/claude-sonnet-4` if you need reasoning support.
|
||||
`kilocode/kilo-auto/balanced` and `x-ai/*` refs skip reasoning-effort injection. Use a concrete
|
||||
model ref such as `kilocode/anthropic/claude-sonnet-4` if you need reasoning support.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Troubleshooting">
|
||||
- If model discovery fails at startup, OpenClaw falls back to the static catalog containing `kilocode/kilo/auto`.
|
||||
- If model discovery fails at startup, OpenClaw falls back to the static catalog containing `kilocode/kilo-auto/balanced`.
|
||||
- Confirm your API key is valid and that your Kilo account has the desired models enabled.
|
||||
- When Gateway runs as a daemon, ensure `KILOCODE_API_KEY` is available to that process (for example in `~/.openclaw/.env` or via `env.shellEnv`).
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ The bundled `minimax` plugin registers MiniMax T2A v2 as a speech provider for `
|
||||
|
||||
- Default TTS model: `speech-2.8-hd`
|
||||
- Default voice: `English_expressive_narrator`
|
||||
- Bundled model ids: `speech-2.8-hd`, `speech-2.8-turbo`, `speech-2.6-hd`, `speech-2.6-turbo`, `speech-02-hd`, `speech-02-turbo`, `speech-01-hd`, `speech-01-turbo`, `speech-01-240228`
|
||||
- Bundled model ids: `speech-2.8-hd`, `speech-2.8-turbo`, `speech-2.6-hd`, `speech-2.6-turbo`, `speech-02-hd`, `speech-02-turbo`, `speech-01-hd`, `speech-01-turbo`
|
||||
- Auth resolution order: `messages.tts.providers.minimax.apiKey`, then `minimax-portal` OAuth/token auth profiles, then Token Plan environment keys (`MINIMAX_OAUTH_TOKEN`, `MINIMAX_CODE_PLAN_KEY`, `MINIMAX_CODING_API_KEY`), then `MINIMAX_API_KEY`
|
||||
- If no TTS host is configured, OpenClaw reuses the configured `minimax-portal` OAuth host and strips Anthropic-compatible path suffixes such as `/anthropic`
|
||||
- Normal audio attachments stay MP3. Voice-note targets (Feishu, Telegram, and other channels that request a voice-note-compatible attachment) are transcoded from MiniMax MP3 to 48kHz Opus with `ffmpeg`, because e.g. the Feishu/Lark file API only accepts `file_type: "opus"` for native audio messages
|
||||
|
||||
+23
-44
@@ -19,32 +19,31 @@ Moonshot and Kimi Coding are **separate providers**, each shipped as a separate
|
||||
|
||||
[//]: # "moonshot-kimi-k2-ids:start"
|
||||
|
||||
| Model ref | Name | Reasoning | Input | Context | Max output |
|
||||
| --------------------------------- | ---------------------- | ---------- | ----------- | --------- | ---------- |
|
||||
| `moonshot/kimi-k2.6` | Kimi K2.6 | No | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k3` | Kimi K3 | Always max | text, image | 1,048,576 | 1,048,576 |
|
||||
| `moonshot/kimi-k2.7-code` | Kimi K2.7 Code | Always on | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2.5` | Kimi K2.5 | No | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2-thinking` | Kimi K2 Thinking | Yes | text | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2-thinking-turbo` | Kimi K2 Thinking Turbo | Yes | text | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2-turbo` | Kimi K2 Turbo | No | text | 256,000 | 16,384 |
|
||||
| Model ref | Name | Reasoning | Input | Context | Max output |
|
||||
| ----------------------------------- | ------------------------ | ---------- | ----------- | --------- | ---------- |
|
||||
| `moonshot/kimi-k2.6` | Kimi K2.6 | No | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k3` | Kimi K3 | Always max | text, image | 1,048,576 | 1,048,576 |
|
||||
| `moonshot/kimi-k2.7-code` | Kimi K2.7 Code | Always on | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2.7-code-highspeed` | Kimi K2.7 Code HighSpeed | Always on | text, image | 262,144 | 262,144 |
|
||||
| `moonshot/kimi-k2.5` | Kimi K2.5 | No | text, image | 262,144 | 262,144 |
|
||||
|
||||
[//]: # "moonshot-kimi-k2-ids:end"
|
||||
|
||||
Catalog cost estimates use Moonshot's published pay-as-you-go rates. The
|
||||
[Kimi K3 pricing](https://platform.kimi.ai/docs/pricing/chat-k3) is $0.30/MTok
|
||||
cache hit, $3.00/MTok input, and $15.00/MTok output; Kimi K2.7 Code is
|
||||
$0.19/MTok cache hit, $0.95/MTok input, $4.00/MTok output; Kimi K2.6 is
|
||||
$0.19/MTok cache hit, $0.95/MTok input, and $4.00/MTok output; its HighSpeed
|
||||
variant is $0.38/MTok cache hit, $1.90/MTok input, and $8.00/MTok output. Kimi K2.6 is
|
||||
$0.16/MTok cache hit, $0.95/MTok input, $4.00/MTok output; Kimi K2.5 is
|
||||
$0.10/MTok cache hit, $0.60/MTok input, $3.00/MTok output. Other catalog
|
||||
entries keep zero-cost placeholders unless you override them in config.
|
||||
$0.10/MTok cache hit, $0.60/MTok input, $3.00/MTok output.
|
||||
|
||||
Kimi K3 always reasons at `reasoning_effort: "max"`. OpenClaw exposes only
|
||||
`/think max`, omits the K2-only `thinking` field, and removes sampling
|
||||
overrides (`temperature`, `top_p`, `n`, `presence_penalty`, and
|
||||
`frequency_penalty`) that K3 fixes to provider defaults. Kimi K2.7 Code also
|
||||
always uses native thinking but requires both `thinking` and
|
||||
`reasoning_effort` to be omitted. Kimi K2.6 remains the onboarding default.
|
||||
`reasoning_effort` to be omitted; the HighSpeed variant uses the same contract.
|
||||
Kimi K2.6 remains the onboarding default.
|
||||
See Moonshot's [Kimi K3 quickstart](https://platform.kimi.ai/docs/guide/kimi-k3-quickstart).
|
||||
|
||||
## Getting started
|
||||
@@ -127,10 +126,8 @@ onboarding.
|
||||
"moonshot/kimi-k2.6": { alias: "Kimi K2.6" },
|
||||
"moonshot/kimi-k3": { alias: "Kimi K3" },
|
||||
"moonshot/kimi-k2.7-code": { alias: "Kimi K2.7 Code" },
|
||||
"moonshot/kimi-k2.7-code-highspeed": { alias: "Kimi K2.7 Code HighSpeed" },
|
||||
"moonshot/kimi-k2.5": { alias: "Kimi K2.5" },
|
||||
"moonshot/kimi-k2-thinking": { alias: "Kimi K2 Thinking" },
|
||||
"moonshot/kimi-k2-thinking-turbo": { alias: "Kimi K2 Thinking Turbo" },
|
||||
"moonshot/kimi-k2-turbo": { alias: "Kimi K2 Turbo" },
|
||||
// moonshot-kimi-k2-aliases:end
|
||||
},
|
||||
},
|
||||
@@ -184,6 +181,15 @@ onboarding.
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2.7-code-highspeed",
|
||||
name: "Kimi K2.7 Code HighSpeed",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2.5",
|
||||
name: "Kimi K2.5",
|
||||
@@ -193,33 +199,6 @@ onboarding.
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-thinking",
|
||||
name: "Kimi K2 Thinking",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-thinking-turbo",
|
||||
name: "Kimi K2 Thinking Turbo",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
},
|
||||
{
|
||||
id: "kimi-k2-turbo",
|
||||
name: "Kimi K2 Turbo",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 256000,
|
||||
maxTokens: 16384,
|
||||
},
|
||||
// moonshot-kimi-k2-models:end
|
||||
],
|
||||
},
|
||||
@@ -234,7 +213,7 @@ onboarding.
|
||||
**Best for:** code-focused tasks via the Kimi Coding endpoint.
|
||||
|
||||
<Note>
|
||||
Kimi Coding uses a different API key and provider prefix (`kimi/...`) than Moonshot (`moonshot/...`). Kimi K3 uses `kimi/k3` for a 256K context or `kimi/k3[1m]` for the 1M tier. Kimi K2.7 Code keeps the stable ref `kimi/kimi-for-coding`; legacy refs `kimi/kimi-code` and `kimi/k2p5` remain accepted and normalize to that model id.
|
||||
Kimi Coding uses a different API key and provider prefix (`kimi/...`) than Moonshot (`moonshot/...`). Current refs are `kimi/k3` for a 256K context, `kimi/k3[1m]` for the 1M tier, `kimi/kimi-for-coding`, and `kimi/kimi-for-coding-highspeed`. Legacy refs `kimi/kimi-code` and `kimi/k2p5` remain accepted and normalize to `kimi/kimi-for-coding`.
|
||||
</Note>
|
||||
|
||||
<Steps>
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
---
|
||||
summary: "Use the Qwen Portal provider id with OpenClaw"
|
||||
read_when:
|
||||
- You want to configure the qwen-oauth provider id
|
||||
- You previously used Qwen Portal OAuth credentials
|
||||
- You need the Qwen Portal endpoint or migration guidance
|
||||
title: "Qwen OAuth / Portal"
|
||||
---
|
||||
|
||||
`qwen-oauth` is the Qwen Portal provider id, registered by the Qwen plugin
|
||||
(`@openclaw/qwen-provider`). It targets the Qwen Portal endpoint at
|
||||
`https://portal.qwen.ai/v1` and keeps older Qwen OAuth / portal setups
|
||||
addressable through a distinct provider id, separate from the canonical `qwen`
|
||||
provider.
|
||||
|
||||
Choose `qwen-oauth` if you already have a working Qwen Portal token, are
|
||||
migrating a legacy Qwen OAuth or Qwen CLI workflow, or need to test the Qwen
|
||||
Portal endpoint specifically. For new setups, prefer
|
||||
[Qwen](/providers/qwen) with the Standard ModelStudio endpoint: it covers new
|
||||
API-key setups, broader endpoint choices, Standard pay-as-you-go, Coding Plan,
|
||||
and the full Qwen plugin catalog.
|
||||
|
||||
## Setup
|
||||
|
||||
Install the Qwen plugin if you have not already:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/qwen-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Provide your portal token through onboarding:
|
||||
|
||||
```bash
|
||||
openclaw onboard --auth-choice qwen-oauth
|
||||
```
|
||||
|
||||
Non-interactive runs read the token from `--qwen-oauth-token <token>`, or set:
|
||||
|
||||
```bash
|
||||
export QWEN_API_KEY="<your-qwen-portal-token>" # pragma: allowlist secret
|
||||
```
|
||||
|
||||
Onboarding stores the token under a `qwen-oauth` auth profile, seeds the portal
|
||||
model catalog, and sets `qwen-oauth/qwen3.5-plus` as the default model when
|
||||
none is configured.
|
||||
|
||||
## Defaults
|
||||
|
||||
- Provider: `qwen-oauth`
|
||||
- Aliases: `qwen-portal`, `qwen-cli`
|
||||
- Base URL: `https://portal.qwen.ai/v1`
|
||||
- Env var: `QWEN_API_KEY`
|
||||
- API style: OpenAI-compatible
|
||||
- Default model: `qwen-oauth/qwen3.5-plus`
|
||||
|
||||
## How this differs from Qwen
|
||||
|
||||
OpenClaw has two Qwen-facing provider ids:
|
||||
|
||||
| Provider | Endpoint family | Best for |
|
||||
| ------------ | -------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `qwen` | Qwen Cloud / Alibaba DashScope and Coding Plan endpoints | New API-key setups, Standard pay-as-you-go, Coding Plan, multimodal DashScope features |
|
||||
| `qwen-oauth` | Qwen Portal endpoint at `portal.qwen.ai/v1` | Existing Qwen Portal tokens and legacy Qwen OAuth / CLI setups |
|
||||
|
||||
Both providers use OpenAI-compatible request shapes, but they are separate auth
|
||||
surfaces. A token stored for `qwen-oauth` should not be treated as a DashScope
|
||||
or ModelStudio key, and a new DashScope key should use the canonical `qwen`
|
||||
provider instead.
|
||||
|
||||
## Models
|
||||
|
||||
The Qwen plugin seeds this static catalog for the Qwen Portal endpoint. All
|
||||
entries use a 65,536-token max output; availability depends on the current Qwen
|
||||
Portal account and token.
|
||||
|
||||
| Model ref | Input | Context | Notes |
|
||||
| --------------------------------- | ----------- | --------- | ------------- |
|
||||
| `qwen-oauth/qwen3.5-plus` | text, image | 1,000,000 | Default model |
|
||||
| `qwen-oauth/qwen3.6-plus` | text, image | 1,000,000 | |
|
||||
| `qwen-oauth/qwen3-max-2026-01-23` | text | 262,144 | |
|
||||
| `qwen-oauth/qwen3-coder-next` | text | 262,144 | |
|
||||
| `qwen-oauth/qwen3-coder-plus` | text | 1,000,000 | |
|
||||
| `qwen-oauth/MiniMax-M2.5` | text | 1,000,000 | Reasoning |
|
||||
| `qwen-oauth/glm-5` | text | 202,752 | |
|
||||
| `qwen-oauth/glm-4.7` | text | 202,752 | |
|
||||
| `qwen-oauth/kimi-k2.5` | text, image | 262,144 | |
|
||||
|
||||
If your account uses ModelStudio / DashScope API keys instead, configure the
|
||||
canonical `qwen` provider:
|
||||
|
||||
```bash
|
||||
openclaw onboard --auth-choice qwen-standard-api-key
|
||||
openclaw models set qwen/qwen3-coder-plus
|
||||
```
|
||||
|
||||
## Migration
|
||||
|
||||
Legacy Qwen Portal OAuth profiles are not refreshable; `openclaw doctor` flags
|
||||
them. If a portal profile stops working, re-run onboarding with a current token
|
||||
or switch to the Standard Qwen provider:
|
||||
|
||||
```bash
|
||||
openclaw onboard --auth-choice qwen-standard-api-key
|
||||
```
|
||||
|
||||
Standard global ModelStudio uses:
|
||||
|
||||
```text
|
||||
https://dashscope-intl.aliyuncs.com/compatible-mode/v1
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Portal OAuth refresh failures: legacy Qwen Portal OAuth profiles are not
|
||||
refreshable. Re-run onboarding with a current token.
|
||||
- Wrong endpoint errors: confirm the model ref starts with `qwen-oauth/` when
|
||||
using a portal token. Use `qwen/` refs only for the canonical Qwen provider.
|
||||
- `QWEN_API_KEY` confusion: both Qwen pages mention this env var, but onboarding
|
||||
stores credentials under the selected provider id. Prefer onboarding when you
|
||||
keep both `qwen` and `qwen-oauth` available on the same machine.
|
||||
|
||||
## Related
|
||||
|
||||
- [Qwen](/providers/qwen)
|
||||
- [Alibaba Model Studio](/providers/alibaba)
|
||||
- [Model providers](/concepts/model-providers)
|
||||
- [All providers](/providers/index)
|
||||
+2
-43
@@ -3,17 +3,15 @@ summary: "Use Qwen Cloud through its OpenClaw plugin"
|
||||
read_when:
|
||||
- You want to use Qwen with OpenClaw
|
||||
- You have an Alibaba Cloud Token Plan subscription
|
||||
- You previously used Qwen OAuth
|
||||
title: "Qwen"
|
||||
---
|
||||
|
||||
Qwen Cloud is an official external OpenClaw provider plugin with canonical id `qwen`. It targets Qwen Cloud / Alibaba DashScope Standard and Coding Plan endpoints, exposes Token Plan as `qwen-token-plan`, keeps `modelstudio` as a compatibility alias, independently owns Alibaba's documented `bailian-token-plan` custom-provider id, and exposes the Qwen Portal token flow as [`qwen-oauth`](/providers/qwen-oauth).
|
||||
Qwen Cloud is an official external OpenClaw provider plugin with canonical id `qwen`. It targets Qwen Cloud / Alibaba DashScope Standard and Coding Plan endpoints, exposes Token Plan as `qwen-token-plan`, keeps `modelstudio` as a compatibility alias, and independently owns Alibaba's documented `bailian-token-plan` custom-provider id.
|
||||
|
||||
| Property | Value |
|
||||
| ---------------------- | ------------------------------------------ |
|
||||
| Provider | `qwen` |
|
||||
| Token Plan provider | `qwen-token-plan` |
|
||||
| Portal provider | [`qwen-oauth`](/providers/qwen-oauth) |
|
||||
| Preferred env var | `QWEN_API_KEY` |
|
||||
| Token Plan env var | `QWEN_TOKEN_PLAN_API_KEY` |
|
||||
| Also accepted (compat) | `MODELSTUDIO_API_KEY`, `DASHSCOPE_API_KEY` |
|
||||
@@ -180,43 +178,6 @@ Choose your plan type and follow the setup steps.
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Qwen OAuth / Portal">
|
||||
**Best for:** a Qwen Portal token against `https://portal.qwen.ai/v1`.
|
||||
|
||||
See [Qwen OAuth / Portal](/providers/qwen-oauth) for the dedicated provider
|
||||
page and migration notes.
|
||||
|
||||
<Steps>
|
||||
<Step title="Provide your portal token">
|
||||
```bash
|
||||
openclaw onboard --auth-choice qwen-oauth
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set a default model">
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "qwen-oauth/qwen3.5-plus" },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
<Step title="Verify the model is available">
|
||||
```bash
|
||||
openclaw models list --provider qwen-oauth
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
`qwen-oauth` uses the same `QWEN_API_KEY` env var name as the Qwen Cloud
|
||||
provider, but stores auth under the `qwen-oauth` provider id when configured
|
||||
through OpenClaw onboarding.
|
||||
</Note>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Plan types and endpoints
|
||||
@@ -225,7 +186,6 @@ Choose your plan type and follow the setup steps.
|
||||
| -------------------------- | ------ | -------------------------- | ---------------------------------------------------------------- |
|
||||
| Coding Plan (subscription) | China | `qwen-api-key-cn` | `coding.dashscope.aliyuncs.com/v1` |
|
||||
| Coding Plan (subscription) | Global | `qwen-api-key` | `coding-intl.dashscope.aliyuncs.com/v1` |
|
||||
| Qwen Portal | Global | `qwen-oauth` | `portal.qwen.ai/v1` |
|
||||
| Standard (pay-as-you-go) | China | `qwen-standard-api-key-cn` | `dashscope.aliyuncs.com/compatible-mode/v1` |
|
||||
| Standard (pay-as-you-go) | Global | `qwen-standard-api-key` | `dashscope-intl.aliyuncs.com/compatible-mode/v1` |
|
||||
| Token Plan (Team Edition) | China | `qwen-token-plan-cn` | `token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1` |
|
||||
@@ -259,7 +219,6 @@ Plan configs omit models that only work on the Standard endpoint.
|
||||
| `qwen/glm-5` | text | 202,752 | GLM |
|
||||
| `qwen/glm-4.7` | text | 202,752 | GLM |
|
||||
| `qwen/kimi-k2.5` | text, image | 262,144 | Moonshot AI via Alibaba |
|
||||
| `qwen-oauth/qwen3.5-plus` | text, image | 1,000,000 | Qwen Portal default |
|
||||
|
||||
<Note>
|
||||
Availability can still vary by endpoint and billing plan even when a model is
|
||||
@@ -311,7 +270,7 @@ requested on/off state.
|
||||
The `qwen` plugin exposes multimodal capabilities on the **Standard** DashScope
|
||||
endpoints only, not the Coding Plan endpoints:
|
||||
|
||||
- **Image and video understanding** via `qwen-vl-max-latest`
|
||||
- **Image and video understanding** via `qwen3.6-plus`
|
||||
- **Wan video generation** via `wan2.6-t2v` (default), `wan2.6-i2v`, `wan2.6-r2v`, `wan2.6-r2v-flash`, `wan2.7-r2v`
|
||||
|
||||
Media understanding is auto-resolved from the configured Qwen auth; no extra
|
||||
|
||||
+19
-32
@@ -32,7 +32,7 @@ Messages API.
|
||||
<Step title="Verify the default model">
|
||||
Onboarding sets the default model to:
|
||||
```text
|
||||
synthetic/hf:MiniMaxAI/MiniMax-M2.5
|
||||
synthetic/hf:MiniMaxAI/MiniMax-M3
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -50,8 +50,8 @@ changes its base URL, override `models.providers.synthetic.baseUrl`.
|
||||
env: { SYNTHETIC_API_KEY: "sk-..." },
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M2.5" },
|
||||
models: { "synthetic/hf:MiniMaxAI/MiniMax-M2.5": { alias: "MiniMax M2.5" } },
|
||||
model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M3" },
|
||||
models: { "synthetic/hf:MiniMaxAI/MiniMax-M3": { alias: "MiniMax M3" } },
|
||||
},
|
||||
},
|
||||
models: {
|
||||
@@ -63,12 +63,12 @@ changes its base URL, override `models.providers.synthetic.baseUrl`.
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "hf:MiniMaxAI/MiniMax-M2.5",
|
||||
name: "MiniMax M2.5",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
id: "hf:MiniMaxAI/MiniMax-M3",
|
||||
name: "MiniMax M3",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 192000,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
},
|
||||
],
|
||||
@@ -80,31 +80,18 @@ changes its base URL, override `models.providers.synthetic.baseUrl`.
|
||||
|
||||
## Built-in catalog
|
||||
|
||||
All Synthetic models use cost `0` (input/output/cache).
|
||||
All Synthetic models use cost `0` (input/output/cache). See Synthetic's
|
||||
[current model list](https://dev.synthetic.new/docs/api/models) for service availability.
|
||||
|
||||
| Model ID | Context window | Max tokens | Reasoning | Input |
|
||||
| ------------------------------------------------------ | -------------- | ---------- | --------- | ------------ |
|
||||
| `hf:MiniMaxAI/MiniMax-M2.5` | 192,000 | 65,536 | no | text |
|
||||
| `hf:moonshotai/Kimi-K2-Thinking` | 256,000 | 8,192 | yes | text |
|
||||
| `hf:zai-org/GLM-4.7` | 198,000 | 128,000 | no | text |
|
||||
| `hf:deepseek-ai/DeepSeek-R1-0528` | 128,000 | 8,192 | no | text |
|
||||
| `hf:deepseek-ai/DeepSeek-V3-0324` | 128,000 | 8,192 | no | text |
|
||||
| `hf:deepseek-ai/DeepSeek-V3.1` | 128,000 | 8,192 | no | text |
|
||||
| `hf:deepseek-ai/DeepSeek-V3.1-Terminus` | 128,000 | 8,192 | no | text |
|
||||
| `hf:deepseek-ai/DeepSeek-V3.2` | 159,000 | 8,192 | no | text |
|
||||
| `hf:meta-llama/Llama-3.3-70B-Instruct` | 128,000 | 8,192 | no | text |
|
||||
| `hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8` | 524,000 | 8,192 | no | text |
|
||||
| `hf:moonshotai/Kimi-K2-Instruct-0905` | 256,000 | 8,192 | no | text |
|
||||
| `hf:moonshotai/Kimi-K2.5` | 256,000 | 8,192 | yes | text + image |
|
||||
| `hf:openai/gpt-oss-120b` | 128,000 | 8,192 | no | text |
|
||||
| `hf:Qwen/Qwen3-235B-A22B-Instruct-2507` | 256,000 | 8,192 | no | text |
|
||||
| `hf:Qwen/Qwen3-Coder-480B-A35B-Instruct` | 256,000 | 8,192 | no | text |
|
||||
| `hf:Qwen/Qwen3-VL-235B-A22B-Instruct` | 250,000 | 8,192 | no | text + image |
|
||||
| `hf:zai-org/GLM-4.5` | 128,000 | 128,000 | no | text |
|
||||
| `hf:zai-org/GLM-4.6` | 198,000 | 128,000 | no | text |
|
||||
| `hf:zai-org/GLM-5` | 256,000 | 128,000 | yes | text + image |
|
||||
| `hf:deepseek-ai/DeepSeek-V3` | 128,000 | 8,192 | no | text |
|
||||
| `hf:Qwen/Qwen3-235B-A22B-Thinking-2507` | 256,000 | 8,192 | yes | text |
|
||||
| Model ID | Context window | Max tokens | Reasoning | Input |
|
||||
| --------------------------------------------------- | -------------- | ---------- | --------- | ------------ |
|
||||
| `hf:MiniMaxAI/MiniMax-M3` | 262,144 | 65,536 | yes | text + image |
|
||||
| `hf:moonshotai/Kimi-K2.7-Code` | 262,144 | 8,192 | yes | text + image |
|
||||
| `hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4` | 262,144 | 8,192 | yes | text |
|
||||
| `hf:openai/gpt-oss-120b` | 131,072 | 8,192 | yes | text |
|
||||
| `hf:Qwen/Qwen3.6-27B` | 262,144 | 81,920 | yes | text + image |
|
||||
| `hf:zai-org/GLM-4.7-Flash` | 196,608 | 131,072 | yes | text |
|
||||
| `hf:zai-org/GLM-5.2` | 524,288 | 131,072 | yes | text |
|
||||
|
||||
<Tip>
|
||||
Model refs use the form `synthetic/<modelId>`. Use
|
||||
|
||||
@@ -78,7 +78,7 @@ shared `video_generate` tool.
|
||||
| Property | Value |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Default video model | `Wan-AI/Wan2.2-T2V-A14B` |
|
||||
| Other models | `Wan-AI/Wan2.2-I2V-A14B`, `minimax/Hailuo-02`, `Kwai/Kling-2.1-Master` |
|
||||
| Other models | `Wan-AI/Wan2.2-I2V-A14B`, `minimax/hailuo-02`, `kwaivgI/kling-2.1-master` |
|
||||
| Modes | text-to-video; image-to-video only with `Wan-AI/Wan2.2-I2V-A14B` (single reference image) |
|
||||
| Duration | 1-10 seconds |
|
||||
| Supported parameters | `size` (parsed as `<width>x<height>`); `aspectRatio`/`resolution` are not read |
|
||||
|
||||
+17
-22
@@ -78,38 +78,33 @@ openclaw models list --all --provider venice
|
||||
You can also run `openclaw configure` and pick **Model/auth provider > Venice AI**.
|
||||
|
||||
<Tip>
|
||||
| Use case | Model | Why |
|
||||
| ------------------------- | ---------------------------------- | ------------------------------------------ |
|
||||
| General chat (default) | `kimi-k2-5` | Strong private reasoning plus vision |
|
||||
| Best overall quality | `claude-opus-4-6` | Strongest anonymized Venice option |
|
||||
| Privacy + coding | `qwen3-coder-480b-a35b-instruct` | Private coding model with large context |
|
||||
| Fast + cheap | `qwen3-4b` | Lightweight reasoning model |
|
||||
| Complex private tasks | `deepseek-v3.2` | Strong reasoning; tool calling disabled |
|
||||
| Uncensored | `venice-uncensored` | No content restrictions |
|
||||
| Use case | Model | Why |
|
||||
| --------------------- | -------------------------------------------- | -------------------------------------- |
|
||||
| General chat (default) | `kimi-k2-5` | Strong private reasoning plus vision |
|
||||
| Best overall quality | `claude-opus-4-6` | Strongest anonymized Venice option |
|
||||
| Privacy + coding | `qwen3-coder-480b-a35b-instruct-turbo` | Private coding model with large context |
|
||||
| Fast + cheap | `llama-3.2-3b` | Compact private model |
|
||||
| Complex private tasks | `deepseek-v3.2` | Strong reasoning; tool calling disabled |
|
||||
| Uncensored | `venice-uncensored-1-2` | Current uncensored Venice model |
|
||||
</Tip>
|
||||
|
||||
## Built-in catalog (38 models)
|
||||
## Built-in catalog (30 models)
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Private models (26) — fully private, no logging">
|
||||
<Accordion title="Private models (20) — fully private, no logging">
|
||||
| Model ID | Name | Context | Notes |
|
||||
| -------------------------------------- | ------------------------------------- | ------- | --------------------------- |
|
||||
| `kimi-k2-5` | Kimi K2.5 | 256k | Default, reasoning, vision |
|
||||
| `kimi-k2-thinking` | Kimi K2 Thinking | 256k | Reasoning |
|
||||
| `llama-3.3-70b` | Llama 3.3 70B | 128k | General |
|
||||
| `llama-3.2-3b` | Llama 3.2 3B | 128k | General |
|
||||
| `hermes-3-llama-3.1-405b` | Hermes 3 Llama 3.1 405B | 128k | General, tools disabled |
|
||||
| `qwen3-235b-a22b-thinking-2507` | Qwen3 235B Thinking | 128k | Reasoning |
|
||||
| `qwen3-235b-a22b-instruct-2507` | Qwen3 235B Instruct | 128k | General |
|
||||
| `qwen3-coder-480b-a35b-instruct` | Qwen3 Coder 480B | 256k | Coding |
|
||||
| `qwen3-coder-480b-a35b-instruct-turbo` | Qwen3 Coder 480B Turbo | 256k | Coding |
|
||||
| `qwen3-5-35b-a3b` | Qwen3.5 35B A3B | 256k | Reasoning, vision |
|
||||
| `qwen3-next-80b` | Qwen3 Next 80B | 256k | General |
|
||||
| `qwen3-vl-235b-a22b` | Qwen3 VL 235B (Vision) | 256k | Vision |
|
||||
| `qwen3-4b` | Venice Small (Qwen3 4B) | 32k | Fast, reasoning |
|
||||
| `deepseek-v3.2` | DeepSeek V3.2 | 160k | Reasoning, tools disabled |
|
||||
| `venice-uncensored` | Venice Uncensored (Dolphin-Mistral) | 32k | Uncensored, tools disabled |
|
||||
| `mistral-31-24b` | Venice Medium (Mistral) | 128k | Vision |
|
||||
| `google-gemma-3-27b-it` | Google Gemma 3 27B Instruct | 198k | Vision |
|
||||
| `openai-gpt-oss-120b` | OpenAI GPT OSS 120B | 128k | General |
|
||||
| `nvidia-nemotron-3-nano-30b-a3b` | NVIDIA Nemotron 3 Nano 30B | 128k | General |
|
||||
@@ -118,11 +113,10 @@ You can also run `openclaw configure` and pick **Model/auth provider > Venice AI
|
||||
| `zai-org-glm-4.7` | GLM 4.7 | 198k | Reasoning |
|
||||
| `zai-org-glm-4.7-flash` | GLM 4.7 Flash | 128k | Reasoning |
|
||||
| `zai-org-glm-5` | GLM 5 | 198k | Reasoning |
|
||||
| `minimax-m21` | MiniMax M2.1 | 198k | Reasoning |
|
||||
| `minimax-m25` | MiniMax M2.5 | 198k | Reasoning |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Anonymized models (12) — via Venice proxy">
|
||||
<Accordion title="Anonymized models (10) — via Venice proxy">
|
||||
| Model ID | Name | Context | Notes |
|
||||
| -------------------------------- | -------------------------------- | ------- | ---------------------------- |
|
||||
| `claude-opus-4-6` | Claude Opus 4.6 (via Venice) | 1M | Reasoning, vision |
|
||||
@@ -134,13 +128,11 @@ You can also run `openclaw configure` and pick **Model/auth provider > Venice AI
|
||||
| `openai-gpt-4o-2024-11-20` | GPT-4o (via Venice) | 128k | Vision |
|
||||
| `openai-gpt-4o-mini-2024-07-18` | GPT-4o Mini (via Venice) | 128k | Vision |
|
||||
| `gemini-3-1-pro-preview` | Gemini 3.1 Pro (via Venice) | 1M | Reasoning, vision |
|
||||
| `gemini-3-pro-preview` | Gemini 3 Pro (via Venice) | 198k | Reasoning, vision |
|
||||
| `gemini-3-flash-preview` | Gemini 3 Flash (via Venice) | 256k | Reasoning, vision |
|
||||
| `grok-41-fast` | Grok 4.1 Fast (via Venice) | 1M | Reasoning, vision |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
Grok-backed Venice models (`grok-41-fast` and similar) get the same tool-schema
|
||||
Grok-backed Venice models (`grok-4-3` and similar) get the same tool-schema
|
||||
compat patch as the native xAI provider, since they share the same upstream
|
||||
tool-call format.
|
||||
|
||||
@@ -151,6 +143,9 @@ refreshes it from the Venice `/models` API and falls back to the seed list if
|
||||
the API is unreachable. The `/models` endpoint is public (no auth needed for
|
||||
listing), but inference requires a valid API key.
|
||||
|
||||
Venice may continue accepting retired model IDs as provider-owned aliases. The
|
||||
OpenClaw catalog advertises only the canonical model IDs returned by `/models`.
|
||||
|
||||
## DeepSeek V4 replay behavior
|
||||
|
||||
If Venice exposes DeepSeek V4 models such as `deepseek-v4-pro` or
|
||||
@@ -185,13 +180,13 @@ openclaw agent --model venice/kimi-k2-5 --message "Quick health check"
|
||||
openclaw agent --model venice/claude-opus-4-6 --message "Summarize this task"
|
||||
|
||||
# Uncensored model
|
||||
openclaw agent --model venice/venice-uncensored --message "Draft options"
|
||||
openclaw agent --model venice/venice-uncensored-1-2 --message "Draft options"
|
||||
|
||||
# Vision model with image
|
||||
openclaw agent --model venice/qwen3-vl-235b-a22b --message "Review attached image"
|
||||
|
||||
# Coding model
|
||||
openclaw agent --model venice/qwen3-coder-480b-a35b-instruct --message "Refactor this function"
|
||||
openclaw agent --model venice/qwen3-coder-480b-a35b-instruct-turbo --message "Refactor this function"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -88,10 +88,6 @@ Both providers are configured from a single API key. Setup registers both automa
|
||||
| ------------------------------------------------- | ------------------------ | ----- | ------- |
|
||||
| `volcengine-plan/ark-code-latest` | Ark Coding Plan | text | 256,000 |
|
||||
| `volcengine-plan/doubao-seed-code` | Doubao Seed Code | text | 256,000 |
|
||||
| `volcengine-plan/doubao-seed-code-preview-251028` | Doubao Seed Code Preview | text | 256,000 |
|
||||
| `volcengine-plan/glm-4.7` | GLM 4.7 Coding | text | 200,000 |
|
||||
| `volcengine-plan/kimi-k2-thinking` | Kimi K2 Thinking | text | 256,000 |
|
||||
| `volcengine-plan/kimi-k2.5` | Kimi K2.5 Coding | text | 256,000 |
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
+18
-31
@@ -22,7 +22,7 @@ providers plus a speech (TTS) provider:
|
||||
| API | OpenAI-compatible chat completions (`openai-completions`) |
|
||||
| Speech contract | `speechProviders: ["xiaomi"]` |
|
||||
| Base URLs | Pay-as-you-go: `https://api.xiaomimimo.com/v1`; Token Plan: `token-plan-{cn,sgp,ams}.xiaomimimo.com/v1` |
|
||||
| Default models | `xiaomi/mimo-v2-flash`, `xiaomi-token-plan/mimo-v2.5-pro` |
|
||||
| Default models | `xiaomi/mimo-v2.5`, `xiaomi-token-plan/mimo-v2.5-pro` |
|
||||
| TTS default | `mimo-v2.5-tts`, voice `mimo_default`; voicedesign model `mimo-v2.5-tts-voicedesign` |
|
||||
|
||||
## Getting started
|
||||
@@ -69,9 +69,8 @@ Onboarding validates the key shape and warns when a `tp-...` key is entered into
|
||||
|
||||
| Model ref | Input | Context | Max output | Reasoning | Notes |
|
||||
| ---------------------- | ----------- | --------- | ---------- | --------- | ------------- |
|
||||
| `xiaomi/mimo-v2-flash` | text | 262,144 | 8,192 | No | Default model |
|
||||
| `xiaomi/mimo-v2-pro` | text | 1,048,576 | 32,000 | Yes | Large context |
|
||||
| `xiaomi/mimo-v2-omni` | text, image | 262,144 | 32,000 | Yes | Multimodal |
|
||||
| `xiaomi/mimo-v2.5` | text, image | 1,048,576 | 131,072 | Yes | Default model |
|
||||
| `xiaomi/mimo-v2.5-pro` | text | 1,048,576 | 131,072 | Yes | Flagship |
|
||||
|
||||
## Token Plan catalog
|
||||
|
||||
@@ -95,10 +94,9 @@ provider is not offered without one of those.
|
||||
|
||||
## Reasoning models
|
||||
|
||||
`mimo-v2-pro`, `mimo-v2-omni`, `mimo-v2.5`, and `mimo-v2.5-pro` support
|
||||
`mimo-v2.5` and `mimo-v2.5-pro` support
|
||||
OpenClaw's [`/think` directive](/tools/thinking) with levels `off`,
|
||||
`minimal`, `low`, `medium`, `high`, `xhigh`, and `max` (default `high`).
|
||||
`mimo-v2-flash` has no reasoning support.
|
||||
|
||||
## Text-to-speech
|
||||
|
||||
@@ -136,8 +134,8 @@ message.
|
||||
```
|
||||
|
||||
Built-in voices: `mimo_default`, `default_zh`, `default_en`, `Mia`, `Chloe`,
|
||||
`Milo`, `Dean`. Preset-voice models (`mimo-v2.5-tts`, `mimo-v2-tts`) use
|
||||
`audio.voice`, so OpenClaw sends `speakerVoice` for those models.
|
||||
`Milo`, `Dean`. The preset-voice model `mimo-v2.5-tts` uses `audio.voice`, so
|
||||
OpenClaw sends `speakerVoice` for that model.
|
||||
|
||||
The voicedesign model `mimo-v2.5-tts-voicedesign` generates the voice from a
|
||||
natural-language style prompt instead of a preset voice id. Set `style` to
|
||||
@@ -171,7 +169,7 @@ mono Opus with `ffmpeg` before delivery.
|
||||
```json5
|
||||
{
|
||||
env: { XIAOMI_API_KEY: "your-key" },
|
||||
agents: { defaults: { model: { primary: "xiaomi/mimo-v2-flash" } } },
|
||||
agents: { defaults: { model: { primary: "xiaomi/mimo-v2.5" } } },
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
@@ -181,28 +179,20 @@ mono Opus with `ffmpeg` before delivery.
|
||||
apiKey: "XIAOMI_API_KEY",
|
||||
models: [
|
||||
{
|
||||
id: "mimo-v2-flash",
|
||||
name: "Xiaomi MiMo V2 Flash",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 8192,
|
||||
id: "mimo-v2.5",
|
||||
name: "Xiaomi MiMo V2.5",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 131072,
|
||||
},
|
||||
{
|
||||
id: "mimo-v2-pro",
|
||||
name: "Xiaomi MiMo V2 Pro",
|
||||
id: "mimo-v2.5-pro",
|
||||
name: "Xiaomi MiMo V2.5 Pro",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 32000,
|
||||
},
|
||||
{
|
||||
id: "mimo-v2-omni",
|
||||
name: "Xiaomi MiMo V2 Omni",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32000,
|
||||
maxTokens: 131072,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -258,11 +248,8 @@ Pricing comes from the bundled manifest (Token Plan models include tiered cache-
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Model details">
|
||||
- **mimo-v2-flash** - lightweight and fast, ideal for general-purpose text tasks. No reasoning support.
|
||||
- **mimo-v2-pro** - supports reasoning with a 1M token context window for long-document workloads.
|
||||
- **mimo-v2-omni** - reasoning-enabled multimodal model that accepts both text and image inputs.
|
||||
- **mimo-v2.5-pro** - Token Plan default with Xiaomi's current V2.5 reasoning stack.
|
||||
- **mimo-v2.5** - Token Plan multimodal V2.5 route.
|
||||
- **mimo-v2.5** - pay-as-you-go default and Token Plan multimodal V2.5 route.
|
||||
- **mimo-v2.5-pro** - flagship reasoning model and Token Plan default.
|
||||
|
||||
<Note>
|
||||
Pay-as-you-go models use the `xiaomi/` prefix. Token Plan models use the `xiaomi-token-plan/` prefix.
|
||||
|
||||
@@ -83,7 +83,7 @@ internal image endpoints remain blocked by default.
|
||||
| OpenRouter image generation | `openrouter/google/gemini-3.1-flash-image-preview` | `OPENROUTER_API_KEY` |
|
||||
| LiteLLM image generation | `litellm/gpt-image-2` | `LITELLM_API_KEY` |
|
||||
| Microsoft Foundry MAI image generation | `microsoft-foundry/<deployment-name>` | `AZURE_OPENAI_API_KEY` or Entra ID |
|
||||
| Google Gemini image generation | `google/gemini-3.1-flash-image-preview` | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
||||
| Google Gemini image generation | `google/gemini-3.1-flash-image` | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
||||
|
||||
The same tool handles text-to-image and reference-image editing. Use `image`
|
||||
for one reference or `images` for multiple. For Krea 2 models on fal, those
|
||||
@@ -101,7 +101,7 @@ backend emits it.
|
||||
| ComfyUI | `workflow` | Yes (1 image, workflow-configured) | `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY` for cloud |
|
||||
| DeepInfra | `black-forest-labs/FLUX-1-schnell` | Yes (1 image) | `DEEPINFRA_API_KEY` |
|
||||
| fal | `fal-ai/flux/dev` | Yes (model-specific limits) | `FAL_KEY` |
|
||||
| Google | `gemini-3.1-flash-image-preview` | Yes (up to 5 images) | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
||||
| Google | `gemini-3.1-flash-image` | Yes (up to 5 images) | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
||||
| LiteLLM | `gpt-image-2` | Yes (up to 5 input images) | `LITELLM_API_KEY` |
|
||||
| Microsoft Foundry | `<deployment-name>` | Yes (MAI-Image-2.5 models only) | `AZURE_OPENAI_API_KEY` or Entra ID (`az login`) |
|
||||
| MiniMax | `image-01` | Yes (subject reference) | `MINIMAX_API_KEY` or MiniMax OAuth (`minimax-portal`) |
|
||||
@@ -209,7 +209,7 @@ translation.
|
||||
timeoutMs: 180_000,
|
||||
fallbacks: [
|
||||
"openrouter/google/gemini-3.1-flash-image-preview",
|
||||
"google/gemini-3.1-flash-image-preview",
|
||||
"google/gemini-3.1-flash-image",
|
||||
"fal/fal-ai/flux/dev",
|
||||
],
|
||||
},
|
||||
@@ -398,8 +398,8 @@ and ComfyUI support 1.
|
||||
OpenClaw forwards `prompt`, `count`, reference images, and
|
||||
Gemini-compatible `aspectRatio` / `resolution` hints to OpenRouter.
|
||||
Current built-in OpenRouter image model shortcuts include
|
||||
`google/gemini-3.1-flash-image-preview`,
|
||||
`google/gemini-3-pro-image-preview`, and `openai/gpt-5.4-image-2`. Use
|
||||
`google/gemini-3.1-flash-image`,
|
||||
`google/gemini-3-pro-image`, and `openai/gpt-5.4-image-2`. Use
|
||||
`action: "list"` to see what your configured plugin exposes.
|
||||
|
||||
</Accordion>
|
||||
|
||||
@@ -38,7 +38,7 @@ title: "Thinking levels"
|
||||
- Google Gemini maps `/think adaptive` to Gemini's provider-owned dynamic thinking. Gemini 3 requests omit a fixed `thinkingLevel`, while Gemini 2.5 requests send `thinkingBudget: -1`; fixed levels still map to the closest Gemini `thinkingLevel` or budget for that model family.
|
||||
- MiniMax M2.x (`minimax/MiniMax-M2*`) on the Anthropic-compatible streaming path defaults to `thinking: { type: "disabled" }` unless you explicitly set thinking in model params or request params. This avoids leaked `reasoning_content` deltas from M2.x's non-native Anthropic stream format. MiniMax-M3 (and M3.x) is exempt: M3 emits proper Anthropic thinking blocks and returns empty content when thinking is disabled, so OpenClaw keeps M3 on the provider's omitted/adaptive thinking path.
|
||||
- Z.AI (`zai/*`) is binary (`on`/`off`) for most GLM models. GLM-5.2 is the exception: it exposes `/think off|low|high|max`, maps `low` and `high` to Z.AI `reasoning_effort: "high"`, and maps `max` to `reasoning_effort: "max"`.
|
||||
- Moonshot API Kimi K3 (`moonshot/kimi-k3`) always thinks at `max`, sends `reasoning_effort: "max"`, omits the K2 `thinking` field and fixed sampling overrides, and preserves K3-supported tool choices. Kimi Code K3 (`kimi/k3` and `kimi/k3[1m]`) exposes `/think off|max`: off sends `thinking.type: "disabled"`, while max sends adaptive thinking with max effort. Kimi K2.7 Code (`moonshot/kimi-k2.7-code`) always thinks, exposes only `on`, and omits both outbound `thinking` and `reasoning_effort`. Other `moonshot/*` models map `/think off` to `thinking: { type: "disabled" }` and any non-`off` level to `thinking: { type: "enabled" }`. When K2 thinking is enabled, Moonshot only accepts `tool_choice` `auto|none`; OpenClaw normalizes incompatible values to `auto`.
|
||||
- Moonshot API Kimi K3 (`moonshot/kimi-k3`) always thinks at `max`, sends `reasoning_effort: "max"`, omits the K2 `thinking` field and fixed sampling overrides, and preserves K3-supported tool choices. Kimi Code K3 (`kimi/k3` and `kimi/k3[1m]`) exposes `/think off|max`: off sends `thinking.type: "disabled"`, while max sends adaptive thinking with max effort. Current Kimi Code refs also include `kimi/kimi-for-coding` and `kimi/kimi-for-coding-highspeed`. Kimi K2.7 Code (`moonshot/kimi-k2.7-code` and `moonshot/kimi-k2.7-code-highspeed`) always thinks, exposes only `on`, and omits both outbound `thinking` and `reasoning_effort`. Other `moonshot/*` models map `/think off` to `thinking: { type: "disabled" }` and any non-`off` level to `thinking: { type: "enabled" }`. When K2 thinking is enabled, Moonshot only accepts `tool_choice` `auto|none`; OpenClaw normalizes incompatible values to `auto`.
|
||||
|
||||
## Resolution order
|
||||
|
||||
|
||||
+1
-1
@@ -938,7 +938,7 @@ Reply -> TTS enabled?
|
||||
<Accordion title="Xiaomi MiMo">
|
||||
<ParamField path="apiKey" type="string">Env: `XIAOMI_API_KEY`.</ParamField>
|
||||
<ParamField path="baseUrl" type="string">Default `https://api.xiaomimimo.com/v1`. Env: `XIAOMI_BASE_URL`.</ParamField>
|
||||
<ParamField path="model" type="string">Default `mimo-v2.5-tts`. Env: `XIAOMI_TTS_MODEL`. Also supports `mimo-v2-tts` and `mimo-v2.5-tts-voicedesign`.</ParamField>
|
||||
<ParamField path="model" type="string">Default `mimo-v2.5-tts`. Env: `XIAOMI_TTS_MODEL`. Also supports `mimo-v2.5-tts-voicedesign`.</ParamField>
|
||||
<ParamField path="speakerVoice" type="string">Default `mimo_default` for preset-voice models. Env: `XIAOMI_TTS_VOICE`. Legacy alias: `voice`. Not sent for `mimo-v2.5-tts-voicedesign`.</ParamField>
|
||||
<ParamField path="format" type='"mp3" | "wav"'>Default `mp3`. Env: `XIAOMI_TTS_FORMAT`.</ParamField>
|
||||
<ParamField path="style" type="string">Optional natural-language style instruction sent as the user message; not spoken. For `mimo-v2.5-tts-voicedesign`, this is the voice-design prompt; OpenClaw supplies a default when omitted.</ParamField>
|
||||
|
||||
@@ -105,8 +105,8 @@ openclaw tasks cancel <lookup>
|
||||
| Provider | Default model | Text | Image ref | Video ref | Auth |
|
||||
| --------------------- | ------------------------------- | :--: | ---------------------------------------------------- | ----------------------------------------------- | ---------------------------------------- |
|
||||
| Alibaba | `wan2.6-t2v` | ✓ | Yes (remote URL) | Yes (remote URL) | `MODELSTUDIO_API_KEY` |
|
||||
| BytePlus (1.0) | `seedance-1-0-pro-250528` | ✓ | Up to 2 images (I2V models only; first + last frame) | - | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus Seedance 1.5 | `seedance-1-5-pro-251215` | ✓ | Up to 2 images (first + last frame via role) | - | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus (bundled) | `seedance-1-0-pro-250528` | ✓ | Up to 2 images (first + last frame) | - | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus 1.5 plugin | `seedance-1-5-pro-251215` | ✓ | Up to 2 images (first + last frame via role) | - | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus Seedance 2.0 | `dreamina-seedance-2-0-260128` | ✓ | Up to 9 reference images | Up to 3 videos | `BYTEPLUS_API_KEY` |
|
||||
| ComfyUI | `workflow` | ✓ | 1 image | - | `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY` |
|
||||
| DeepInfra | `Pixverse/Pixverse-T2V` | ✓ | - | - | `DEEPINFRA_API_KEY` |
|
||||
@@ -322,24 +322,21 @@ only the explicit `model`, `primary`, and `fallbacks` entries.
|
||||
Uses DashScope / Model Studio async endpoint. Reference images and
|
||||
videos must be remote `http(s)` URLs.
|
||||
</Accordion>
|
||||
<Accordion title="BytePlus (1.0)">
|
||||
<Accordion title="BytePlus (bundled)">
|
||||
Provider id: `byteplus`.
|
||||
|
||||
Models: `seedance-1-0-pro-250528` (default),
|
||||
`seedance-1-0-pro-t2v-250528`, `seedance-1-0-pro-fast-251015`,
|
||||
`seedance-1-0-lite-t2v-250428`, `seedance-1-0-lite-i2v-250428`.
|
||||
`seedance-1-5-pro-251215`.
|
||||
|
||||
T2V models (`*-t2v-*`) do not accept image inputs; I2V models and
|
||||
general `*-pro-*` models support a single reference image (first
|
||||
frame). Pass the image positionally or set `role: "first_frame"`.
|
||||
T2V model IDs are automatically switched to the corresponding I2V
|
||||
variant when an image is provided.
|
||||
Uses the unified `content[]` API. Supports up to 2 input images
|
||||
(`first_frame` + `last_frame`). Pass images positionally or set each
|
||||
image's `role` explicitly.
|
||||
|
||||
Supported `providerOptions` keys: `seed` (number), `draft` (boolean -
|
||||
forces 480p), `camera_fixed` (boolean).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="BytePlus Seedance 1.5">
|
||||
<Accordion title="BytePlus Seedance 1.5 plugin">
|
||||
Requires the [`@openclaw/byteplus-modelark`](https://www.npmjs.com/package/@openclaw/byteplus-modelark)
|
||||
plugin (external, not bundled). Provider id: `byteplus-seedance15`. Model:
|
||||
`seedance-1-5-pro-251215`.
|
||||
|
||||
@@ -283,14 +283,14 @@ describe("bedrock discovery", () => {
|
||||
.mockResolvedValueOnce({
|
||||
inferenceProfileSummaries: [
|
||||
{
|
||||
inferenceProfileId: "jp.anthropic.claude-sonnet-4-6-v1:0",
|
||||
inferenceProfileId: "jp.anthropic.claude-sonnet-4-6",
|
||||
inferenceProfileName: "JP Claude Sonnet 4.6",
|
||||
status: "ACTIVE",
|
||||
type: "SYSTEM_DEFINED",
|
||||
models: [
|
||||
{
|
||||
modelArn:
|
||||
"arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-sonnet-4-6-v1:0",
|
||||
"arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-sonnet-4-6",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -300,7 +300,7 @@ describe("bedrock discovery", () => {
|
||||
const models = await discoverBedrockModels({ region: "ap-northeast-1", clientFactory });
|
||||
|
||||
expectModelFields(models[0], {
|
||||
id: "jp.anthropic.claude-sonnet-4-6-v1:0",
|
||||
id: "jp.anthropic.claude-sonnet-4-6",
|
||||
contextWindow: 1_000_000,
|
||||
});
|
||||
});
|
||||
@@ -729,7 +729,7 @@ describe("bedrock discovery", () => {
|
||||
models: [
|
||||
{
|
||||
modelArn:
|
||||
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-opus-4-6-v1:0",
|
||||
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-opus-4-6-v1",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -743,7 +743,7 @@ describe("bedrock discovery", () => {
|
||||
contextWindow: 1_000_000,
|
||||
maxTokens: 4096,
|
||||
input: ["text"],
|
||||
params: { canonicalModelId: "claude-opus-4-6-v1:0" },
|
||||
params: { canonicalModelId: "claude-opus-4-6-v1" },
|
||||
thinkingLevelMap: { xhigh: null, max: "max" },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -74,9 +74,7 @@ const KNOWN_CONTEXT_WINDOWS: Record<string, number> = {
|
||||
"anthropic.claude-opus-4-8": 1_000_000,
|
||||
"anthropic.claude-opus-4-7": 1_000_000,
|
||||
"anthropic.claude-opus-4-6-v1": 1_000_000,
|
||||
"anthropic.claude-opus-4-6-v1:0": 1_000_000,
|
||||
"anthropic.claude-sonnet-4-6": 1_000_000,
|
||||
"anthropic.claude-sonnet-4-6-v1:0": 1_000_000,
|
||||
"anthropic.claude-sonnet-4-5-20250929-v1:0": 200_000,
|
||||
"anthropic.claude-sonnet-4-20250514-v1:0": 200_000,
|
||||
"anthropic.claude-opus-4-5-20251101-v1:0": 200_000,
|
||||
|
||||
@@ -233,7 +233,7 @@ describe("Bedrock thinking effort mapping", () => {
|
||||
|
||||
it("does not force adaptive thinking for optional Claude models when callers omit reasoning", () => {
|
||||
const model = bedrockModel({
|
||||
id: "anthropic.claude-sonnet-4-6-v1:0",
|
||||
id: "anthropic.claude-sonnet-4-6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
reasoning: true,
|
||||
});
|
||||
@@ -357,7 +357,7 @@ describe("Bedrock thinking effort mapping", () => {
|
||||
expect(
|
||||
testing.mapThinkingLevelToEffort(
|
||||
bedrockModel({
|
||||
id: "anthropic.claude-sonnet-4-6-v1:0",
|
||||
id: "anthropic.claude-sonnet-4-6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
}),
|
||||
"max",
|
||||
@@ -369,7 +369,7 @@ describe("Bedrock thinking effort mapping", () => {
|
||||
expect(
|
||||
testing.mapThinkingLevelToEffort(
|
||||
bedrockModel({
|
||||
id: "anthropic.claude-opus-4-6-v1:0",
|
||||
id: "anthropic.claude-opus-4-6-v1",
|
||||
name: "Claude Opus 4.6",
|
||||
}),
|
||||
"xhigh",
|
||||
|
||||
@@ -68,9 +68,8 @@ describe("arcee provider plugin", () => {
|
||||
expect(arceeConfig?.baseUrl).toBe("https://openrouter.ai/api/v1");
|
||||
expect(arceeConfig?.api).toBe("openai-completions");
|
||||
expect(config?.models?.providers?.arcee?.models?.map((model) => model.id)).toEqual([
|
||||
"arcee/trinity-mini",
|
||||
"arcee/trinity-large-preview",
|
||||
"arcee/trinity-large-thinking",
|
||||
"arcee-ai/trinity-large-preview",
|
||||
"arcee-ai/trinity-large-thinking",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -116,12 +115,11 @@ describe("arcee provider plugin", () => {
|
||||
|
||||
expect(catalogProvider.baseUrl).toBe("https://openrouter.ai/api/v1");
|
||||
expect(catalogProvider.models?.map((model) => model.id)).toEqual([
|
||||
"arcee/trinity-mini",
|
||||
"arcee/trinity-large-preview",
|
||||
"arcee/trinity-large-thinking",
|
||||
"arcee-ai/trinity-large-preview",
|
||||
"arcee-ai/trinity-large-thinking",
|
||||
]);
|
||||
const thinkingCompat = catalogProvider.models?.find(
|
||||
(model) => model.id === "arcee/trinity-large-thinking",
|
||||
(model) => model.id === "arcee-ai/trinity-large-thinking",
|
||||
)?.compat;
|
||||
expect(thinkingCompat?.supportsTools).toBe(false);
|
||||
expect(thinkingCompat?.supportsReasoningEffort).toBe(false);
|
||||
@@ -140,7 +138,7 @@ describe("arcee provider plugin", () => {
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
},
|
||||
} as never);
|
||||
expect(openRouterModel?.id).toBe("arcee/trinity-large-thinking");
|
||||
expect(openRouterModel?.id).toBe("arcee-ai/trinity-large-thinking");
|
||||
|
||||
expect(
|
||||
provider.normalizeResolvedModel?.({
|
||||
@@ -179,7 +177,7 @@ describe("arcee provider plugin", () => {
|
||||
baseUrl: "https://openrouter.ai/v1",
|
||||
},
|
||||
} as never);
|
||||
expect(normalizedModel?.id).toBe("arcee/trinity-large-thinking");
|
||||
expect(normalizedModel?.id).toBe("arcee-ai/trinity-large-thinking");
|
||||
expect(normalizedModel?.baseUrl).toBe("https://openrouter.ai/api/v1");
|
||||
|
||||
expect(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Arcee provider catalog builders. Direct Arcee uses native ids; OpenRouter
|
||||
* catalogs normalize ids to the `arcee/*` namespace.
|
||||
* catalogs expose only currently served models under OpenRouter's `arcee-ai/*`
|
||||
* namespace.
|
||||
*/
|
||||
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { buildArceeModelDefinition, ARCEE_BASE_URL, ARCEE_MODEL_CATALOG } from "./models.js";
|
||||
@@ -8,6 +9,7 @@ import { buildArceeModelDefinition, ARCEE_BASE_URL, ARCEE_MODEL_CATALOG } from "
|
||||
/** Canonical OpenRouter API base URL for Arcee-routed models. */
|
||||
export const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
||||
const OPENROUTER_LEGACY_BASE_URL = "https://openrouter.ai/v1";
|
||||
const ARCEE_OPENROUTER_MODEL_IDS = new Set(["trinity-large-preview", "trinity-large-thinking"]);
|
||||
|
||||
function normalizeBaseUrl(baseUrl: string | undefined): string {
|
||||
return (baseUrl ?? "").trim().replace(/\/+$/, "");
|
||||
@@ -25,13 +27,14 @@ export function normalizeArceeOpenRouterBaseUrl(baseUrl: string | undefined): st
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Convert a bare Arcee model id to the OpenRouter `arcee/*` id. */
|
||||
/** Convert a bare or legacy Arcee model id to OpenRouter's `arcee-ai/*` id. */
|
||||
export function toArceeOpenRouterModelId(modelId: string): string {
|
||||
const normalized = modelId.trim();
|
||||
if (!normalized || normalized.startsWith("arcee/")) {
|
||||
if (!normalized || normalized.startsWith("arcee-ai/")) {
|
||||
return normalized;
|
||||
}
|
||||
return `arcee/${normalized}`;
|
||||
const bareId = normalized.startsWith("arcee/") ? normalized.slice("arcee/".length) : normalized;
|
||||
return `arcee-ai/${bareId}`;
|
||||
}
|
||||
|
||||
/** Build direct Arcee catalog models. */
|
||||
@@ -41,9 +44,9 @@ export function buildArceeCatalogModels(): NonNullable<ModelProviderConfig["mode
|
||||
|
||||
/** Build OpenRouter-routed Arcee catalog models. */
|
||||
export function buildArceeOpenRouterCatalogModels(): NonNullable<ModelProviderConfig["models"]> {
|
||||
return buildArceeCatalogModels().map((model) =>
|
||||
Object.assign({}, model, { id: toArceeOpenRouterModelId(model.id) }),
|
||||
);
|
||||
return buildArceeCatalogModels()
|
||||
.filter((model) => ARCEE_OPENROUTER_MODEL_IDS.has(model.id))
|
||||
.map((model) => Object.assign({}, model, { id: toArceeOpenRouterModelId(model.id) }));
|
||||
}
|
||||
|
||||
/** Build the direct Arcee provider config. */
|
||||
|
||||
@@ -32,6 +32,11 @@ describe("byteplus plugin", () => {
|
||||
expect(planEntry?.reasoning).toBe(codingModel.reasoning);
|
||||
expect(planEntry?.input).toEqual([...codingModel.input]);
|
||||
expect(planEntry?.contextWindow).toBe(codingModel.contextWindow);
|
||||
expect(BYTEPLUS_CODING_MODEL_CATALOG.map((entry) => entry.id)).toEqual([
|
||||
"ark-code-latest",
|
||||
"glm-4.7",
|
||||
"kimi-k2.5",
|
||||
]);
|
||||
});
|
||||
|
||||
it("declares its coding provider auth alias in the manifest", () => {
|
||||
@@ -47,11 +52,8 @@ describe("byteplus plugin", () => {
|
||||
it("keeps Kimi catalog metadata aligned with provider capabilities", () => {
|
||||
const standardKimi = BYTEPLUS_MODEL_CATALOG.find((entry) => entry.id === "kimi-k2-5-260127");
|
||||
const planKimi = BYTEPLUS_CODING_MODEL_CATALOG.find((entry) => entry.id === "kimi-k2.5");
|
||||
const thinkingKimi = BYTEPLUS_CODING_MODEL_CATALOG.find(
|
||||
(entry) => entry.id === "kimi-k2-thinking",
|
||||
);
|
||||
|
||||
for (const entry of [standardKimi, planKimi, thinkingKimi]) {
|
||||
for (const entry of [standardKimi, planKimi]) {
|
||||
expect(entry?.reasoning).toBe(true);
|
||||
expect(entry?.maxTokens).toBe(32768);
|
||||
expect(entry?.cost?.input).toBe(0.6);
|
||||
|
||||
@@ -82,19 +82,6 @@
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "doubao-seed-code",
|
||||
"name": "Doubao Seed Code",
|
||||
"input": ["text"],
|
||||
"contextWindow": 256000,
|
||||
"maxTokens": 4096,
|
||||
"cost": {
|
||||
"input": 0.0001,
|
||||
"output": 0.0002,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "glm-4.7",
|
||||
"name": "GLM 4.7 Coding",
|
||||
@@ -108,20 +95,6 @@
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2-thinking",
|
||||
"name": "Kimi K2 Thinking",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 256000,
|
||||
"maxTokens": 32768,
|
||||
"cost": {
|
||||
"input": 0.6,
|
||||
"output": 2.5,
|
||||
"cacheRead": 0.12,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2.5",
|
||||
"name": "Kimi K2.5 Coding",
|
||||
|
||||
@@ -93,7 +93,7 @@ function mockSuccessfulBytePlusTask(params?: { model?: string }) {
|
||||
content: {
|
||||
video_url: "https://example.com/byteplus.mp4",
|
||||
},
|
||||
model: params?.model ?? "seedance-1-0-lite-t2v-250428",
|
||||
model: params?.model ?? "seedance-1-0-pro-250528",
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce({
|
||||
@@ -186,7 +186,10 @@ function makeOversizedJsonStream(): {
|
||||
|
||||
describe("byteplus video generation provider", () => {
|
||||
it("declares explicit mode capabilities", () => {
|
||||
expectExplicitVideoGenerationCapabilities(buildBytePlusVideoGenerationProvider());
|
||||
const provider = buildBytePlusVideoGenerationProvider();
|
||||
expectExplicitVideoGenerationCapabilities(provider);
|
||||
expect(provider.defaultModel).toBe("seedance-1-0-pro-250528");
|
||||
expect(provider.models).toEqual(["seedance-1-0-pro-250528", "seedance-1-5-pro-251215"]);
|
||||
});
|
||||
|
||||
it("creates a content-generation task, polls, and downloads the video", async () => {
|
||||
@@ -195,7 +198,7 @@ describe("byteplus video generation provider", () => {
|
||||
const provider = buildBytePlusVideoGenerationProvider();
|
||||
const result = await provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "A lantern floats upward into the night sky",
|
||||
cfg: {},
|
||||
});
|
||||
@@ -236,20 +239,20 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "short video",
|
||||
cfg: { agents: { defaults: { mediaMaxMb: 0.000001 } } },
|
||||
}),
|
||||
).rejects.toThrow("BytePlus generated video download exceeds 1 bytes");
|
||||
});
|
||||
|
||||
it("switches t2v image requests to i2v models and lowercases resolution", async () => {
|
||||
mockSuccessfulBytePlusTask({ model: "seedance-1-0-lite-i2v-250428" });
|
||||
it("keeps the unified model for image requests and lowercases resolution", async () => {
|
||||
mockSuccessfulBytePlusTask({ model: "seedance-1-0-pro-250528" });
|
||||
|
||||
const provider = buildBytePlusVideoGenerationProvider();
|
||||
await provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "Animate this still image",
|
||||
resolution: "720P",
|
||||
inputImages: [{ url: "https://example.com/first-frame.png" }],
|
||||
@@ -257,7 +260,7 @@ describe("byteplus video generation provider", () => {
|
||||
});
|
||||
|
||||
expect(requireBytePlusPostBody()).toEqual({
|
||||
model: "seedance-1-0-lite-i2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
resolution: "720p",
|
||||
content: [
|
||||
{ type: "text", text: "Animate this still image" },
|
||||
@@ -351,7 +354,7 @@ describe("byteplus video generation provider", () => {
|
||||
const provider = buildBytePlusVideoGenerationProvider();
|
||||
const result = await provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "A lantern floats upward into the night sky",
|
||||
cfg: {},
|
||||
});
|
||||
@@ -378,7 +381,7 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "bad create response",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -404,7 +407,7 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "missing status",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -428,7 +431,7 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "malformed content",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -450,7 +453,7 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "oversized submit response",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -481,7 +484,7 @@ describe("byteplus video generation provider", () => {
|
||||
await expect(
|
||||
provider.generateVideo({
|
||||
provider: "byteplus",
|
||||
model: "seedance-1-0-lite-t2v-250428",
|
||||
model: "seedance-1-0-pro-250528",
|
||||
prompt: "oversized poll response",
|
||||
cfg: {},
|
||||
}),
|
||||
|
||||
@@ -31,7 +31,7 @@ import type {
|
||||
} from "openclaw/plugin-sdk/video-generation";
|
||||
import { BYTEPLUS_BASE_URL } from "./models.js";
|
||||
|
||||
const DEFAULT_BYTEPLUS_VIDEO_MODEL = "seedance-1-0-lite-t2v-250428";
|
||||
const DEFAULT_BYTEPLUS_VIDEO_MODEL = "seedance-1-0-pro-250528";
|
||||
const DEFAULT_TIMEOUT_MS = 120_000;
|
||||
const POLL_INTERVAL_MS = 5_000;
|
||||
const MAX_POLL_ATTEMPTS = 120;
|
||||
@@ -231,12 +231,7 @@ export function buildBytePlusVideoGenerationProvider(): VideoGenerationProvider
|
||||
id: "byteplus",
|
||||
label: "BytePlus",
|
||||
defaultModel: DEFAULT_BYTEPLUS_VIDEO_MODEL,
|
||||
models: [
|
||||
DEFAULT_BYTEPLUS_VIDEO_MODEL,
|
||||
"seedance-1-0-lite-i2v-250428",
|
||||
"seedance-1-0-pro-250528",
|
||||
"seedance-1-5-pro-251215",
|
||||
],
|
||||
models: [DEFAULT_BYTEPLUS_VIDEO_MODEL, "seedance-1-5-pro-251215"],
|
||||
isConfigured: ({ agentDir }) =>
|
||||
isProviderApiKeyConfigured({
|
||||
provider: "byteplus",
|
||||
@@ -302,16 +297,7 @@ export function buildBytePlusVideoGenerationProvider(): VideoGenerationProvider
|
||||
capability: "video",
|
||||
transport: "http",
|
||||
});
|
||||
// Seedance 1.0 has separate T2V and I2V model IDs (e.g. seedance-1-0-lite-t2v-250428 vs
|
||||
// seedance-1-0-lite-i2v-250428). When input images are provided with a T2V model, auto-
|
||||
// switch to the corresponding I2V variant so the API does not reject with task_type mismatch.
|
||||
// 1.5 Pro uses a single model ID for both modes and is unaffected by this substitution.
|
||||
const hasInputImages = (req.inputImages?.length ?? 0) > 0;
|
||||
const requestedModel = normalizeOptionalString(req.model) || DEFAULT_BYTEPLUS_VIDEO_MODEL;
|
||||
const resolvedModel =
|
||||
hasInputImages && requestedModel.includes("-t2v-")
|
||||
? requestedModel.replace("-t2v-", "-i2v-")
|
||||
: requestedModel;
|
||||
const resolvedModel = normalizeOptionalString(req.model) || DEFAULT_BYTEPLUS_VIDEO_MODEL;
|
||||
|
||||
const content: Array<Record<string, unknown>> = [{ type: "text", text: req.prompt }];
|
||||
const imageUrl = resolveBytePlusImageUrl(req);
|
||||
|
||||
@@ -26,7 +26,7 @@ export default defineSingleProviderPluginEntry({
|
||||
defaultModel: CEREBRAS_DEFAULT_MODEL_REF,
|
||||
applyConfig: (cfg) => applyCerebrasConfig(cfg),
|
||||
noteMessage: [
|
||||
"Cerebras provides high-speed OpenAI-compatible inference for GPT OSS, GLM, Qwen, and Llama models.",
|
||||
"Cerebras provides high-speed OpenAI-compatible inference for GPT OSS and GLM models.",
|
||||
"Get your API key at: https://cloud.cerebras.ai",
|
||||
].join("\n"),
|
||||
noteTitle: "Cerebras",
|
||||
|
||||
@@ -51,32 +51,6 @@
|
||||
"cacheRead": 0.35,
|
||||
"cacheWrite": 0.75
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "qwen-3-235b-a22b-instruct-2507",
|
||||
"name": "Qwen 3 235B Instruct",
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 8192,
|
||||
"cost": {
|
||||
"input": 0.6,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0.6,
|
||||
"cacheWrite": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "llama3.1-8b",
|
||||
"name": "Llama 3.1 8B",
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 8192,
|
||||
"cost": {
|
||||
"input": 0.1,
|
||||
"output": 0.1,
|
||||
"cacheRead": 0.1,
|
||||
"cacheWrite": 0.1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,9 +4,20 @@ import { clearLiveCatalogCacheForTests } from "openclaw/plugin-sdk/provider-cata
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildChutesModelDefinition,
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
CHUTES_MODEL_CATALOG,
|
||||
discoverChutesModels,
|
||||
} from "./models.js";
|
||||
import { applyChutesConfig } from "./onboard.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const EXPECTED_STATIC_MODEL_IDS = [
|
||||
"deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
"moonshotai/Kimi-K2.5-TEE",
|
||||
"zai-org/GLM-5-TEE",
|
||||
"MiniMaxAI/MiniMax-M2.5-TEE",
|
||||
"Qwen/Qwen3.5-397B-A17B-TEE",
|
||||
];
|
||||
|
||||
function restoreEnvVar(name: string, value: string | undefined): void {
|
||||
if (value === undefined) {
|
||||
@@ -105,20 +116,54 @@ describe("chutes-models", () => {
|
||||
expect(def.compat.supportsUsageInStreaming).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps Qwen VL image limits in the runtime catalog", () => {
|
||||
const visionModelIds = ["Qwen/Qwen2.5-VL-32B-Instruct", "Qwen/Qwen3-VL-235B-A22B-Instruct"];
|
||||
it("keeps image-capable fallback models in the runtime catalog", () => {
|
||||
const visionModelIds = ["moonshotai/Kimi-K2.5-TEE", "Qwen/Qwen3.5-397B-A17B-TEE"];
|
||||
for (const id of visionModelIds) {
|
||||
const model = CHUTES_MODEL_CATALOG.find((candidate) => candidate.id === id);
|
||||
expect(model).toBeDefined();
|
||||
if (!model) {
|
||||
throw new Error(`expected ${id}`);
|
||||
}
|
||||
expect(buildChutesModelDefinition(model).mediaInput).toEqual({
|
||||
image: { maxPixels: 12845056, preferredSidePx: 2048, tokenMode: "provider" },
|
||||
});
|
||||
expect(buildChutesModelDefinition(model).input).toContain("image");
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps manifest, runtime catalog, defaults, and aliases aligned", () => {
|
||||
const manifestIds = manifest.modelCatalog.providers.chutes.models.map((model) => model.id);
|
||||
const runtimeIds = CHUTES_MODEL_CATALOG.map((model) => model.id);
|
||||
expect(manifestIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
|
||||
expect(runtimeIds).toEqual(EXPECTED_STATIC_MODEL_IDS);
|
||||
|
||||
const cfg = applyChutesConfig({});
|
||||
expect(cfg.models?.providers?.chutes?.models.map((model) => model.id)).toEqual(
|
||||
EXPECTED_STATIC_MODEL_IDS,
|
||||
);
|
||||
expect(cfg.agents?.defaults?.model).toEqual({
|
||||
primary: CHUTES_DEFAULT_MODEL_REF,
|
||||
fallbacks: ["chutes/deepseek-ai/DeepSeek-V3.2-TEE", "chutes/moonshotai/Kimi-K2.5-TEE"],
|
||||
});
|
||||
expect(cfg.agents?.defaults?.imageModel).toEqual({
|
||||
primary: "chutes/moonshotai/Kimi-K2.5-TEE",
|
||||
fallbacks: ["chutes/Qwen/Qwen3.5-397B-A17B-TEE"],
|
||||
});
|
||||
expect(cfg.agents?.defaults?.models?.["chutes-fast"]).toBeUndefined();
|
||||
expect(cfg.agents?.defaults?.models?.["chutes-pro"]?.alias).toBe(
|
||||
"chutes/deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
);
|
||||
expect(cfg.agents?.defaults?.models?.["chutes-vision"]?.alias).toBe(
|
||||
"chutes/moonshotai/Kimi-K2.5-TEE",
|
||||
);
|
||||
const configuredTargets = [
|
||||
CHUTES_DEFAULT_MODEL_REF,
|
||||
"chutes/deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
"chutes/moonshotai/Kimi-K2.5-TEE",
|
||||
"chutes/Qwen/Qwen3.5-397B-A17B-TEE",
|
||||
];
|
||||
expect(
|
||||
configuredTargets.every((modelRef) => runtimeIds.includes(modelRef.slice("chutes/".length))),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("discoverChutesModels returns static catalog when accessToken is empty", async () => {
|
||||
const models = await discoverChutesModels("");
|
||||
expect(models).toHaveLength(CHUTES_MODEL_CATALOG.length);
|
||||
@@ -128,14 +173,14 @@ describe("chutes-models", () => {
|
||||
it("discoverChutesModels returns static catalog in test env by default", async () => {
|
||||
const models = await discoverChutesModels("test-token");
|
||||
expect(models).toHaveLength(CHUTES_MODEL_CATALOG.length);
|
||||
expect(requireChutesModel(models, 0).id).toBe("Qwen/Qwen3-32B");
|
||||
expect(requireChutesModel(models, 0).id).toBe("deepseek-ai/DeepSeek-V3.2-TEE");
|
||||
});
|
||||
|
||||
it("discoverChutesModels correctly maps API response when not in test env", async () => {
|
||||
const mockFetch = vi.fn().mockResolvedValue(
|
||||
jsonResponse({
|
||||
data: [
|
||||
{ id: "zai-org/GLM-4.7-TEE" },
|
||||
{ id: "zai-org/GLM-5-TEE" },
|
||||
{
|
||||
id: "new-provider/new-model-r1",
|
||||
supported_features: ["reasoning"],
|
||||
@@ -154,7 +199,7 @@ describe("chutes-models", () => {
|
||||
if (models.length === 3) {
|
||||
const firstModel = requireChutesModel(models, 0);
|
||||
const secondModel = requireChutesModel(models, 1);
|
||||
expect(firstModel.id).toBe("zai-org/GLM-4.7-TEE");
|
||||
expect(firstModel.id).toBe("zai-org/GLM-5-TEE");
|
||||
expect(secondModel.reasoning).toBe(true);
|
||||
if (!secondModel.compat) {
|
||||
throw new Error("expected Chutes API model compat");
|
||||
@@ -207,30 +252,30 @@ describe("chutes-models", () => {
|
||||
jsonResponse({
|
||||
data: [
|
||||
{
|
||||
id: "Qwen/Qwen3-32B",
|
||||
name: "Qwen/Qwen3-32B",
|
||||
id: "Qwen/Qwen3-32B-TEE",
|
||||
name: "Qwen/Qwen3-32B-TEE",
|
||||
supported_features: ["reasoning"],
|
||||
input_modalities: ["text"],
|
||||
context_length: 40960,
|
||||
max_output_length: 40960,
|
||||
pricing: { prompt: 0.08, completion: 0.24 },
|
||||
pricing: { prompt: 0.104, completion: 0.416 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
name: "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
id: "unsloth/Mistral-Nemo-Instruct-2407-TEE",
|
||||
name: "unsloth/Mistral-Nemo-Instruct-2407-TEE",
|
||||
input_modalities: ["text"],
|
||||
context_length: 131072,
|
||||
max_output_length: 131072,
|
||||
pricing: { prompt: 0.02, completion: 0.04 },
|
||||
pricing: { prompt: 0.0245, completion: 0.0978 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
name: "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
id: "zai-org/GLM-5.2-TEE",
|
||||
name: "zai-org/GLM-5.2-TEE",
|
||||
supported_features: ["reasoning"],
|
||||
input_modalities: ["text"],
|
||||
context_length: 131072,
|
||||
max_output_length: 65536,
|
||||
pricing: { prompt: 0.28, completion: 0.42 },
|
||||
context_length: 1048576,
|
||||
max_output_length: 65535,
|
||||
pricing: { prompt: 1.4, completion: 4.4 },
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
+13
-437
@@ -5,6 +5,7 @@ import {
|
||||
getCachedLiveProviderModelRows,
|
||||
LiveModelCatalogHttpError,
|
||||
} from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
||||
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
||||
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
@@ -14,459 +15,34 @@ import {
|
||||
normalizeOptionalString,
|
||||
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { isChutesModelDiscoveryTestEnvironment } from "./model-discovery-env.js";
|
||||
import manifest from "./openclaw.plugin.json" with { type: "json" };
|
||||
|
||||
const log = createSubsystemLogger("chutes-models");
|
||||
|
||||
const CHUTES_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
|
||||
providerId: "chutes",
|
||||
catalog: manifest.modelCatalog.providers.chutes,
|
||||
});
|
||||
|
||||
/** Base URL for Chutes OpenAI-compatible inference. */
|
||||
export const CHUTES_BASE_URL = "https://llm.chutes.ai/v1";
|
||||
export const CHUTES_BASE_URL = CHUTES_MANIFEST_PROVIDER.baseUrl;
|
||||
/** Default Chutes model id used for onboarding. */
|
||||
export const CHUTES_DEFAULT_MODEL_ID = "zai-org/GLM-4.7-TEE";
|
||||
export const CHUTES_DEFAULT_MODEL_ID = "zai-org/GLM-5-TEE";
|
||||
/** Default Chutes model ref used for onboarding. */
|
||||
export const CHUTES_DEFAULT_MODEL_REF = `chutes/${CHUTES_DEFAULT_MODEL_ID}`;
|
||||
|
||||
const CHUTES_DEFAULT_CONTEXT_WINDOW = 128000;
|
||||
const CHUTES_DEFAULT_MAX_TOKENS = 4096;
|
||||
|
||||
/** Bundled fallback Chutes model catalog. */
|
||||
export const CHUTES_MODEL_CATALOG: ModelDefinitionConfig[] = [
|
||||
{
|
||||
id: "Qwen/Qwen3-32B",
|
||||
name: "Qwen/Qwen3-32B",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 40960,
|
||||
maxTokens: 40960,
|
||||
cost: { input: 0.08, output: 0.24, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
name: "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.02, output: 0.04, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
name: "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.25, output: 1, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
|
||||
name: "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.08, output: 0.55, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-oss-120b-TEE",
|
||||
name: "openai/gpt-oss-120b-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.05, output: 0.45, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
|
||||
name: "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.03, output: 0.11, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
name: "deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.28, output: 0.42, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-4.7-TEE",
|
||||
name: "zai-org/GLM-4.7-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 202752,
|
||||
maxTokens: 65535,
|
||||
cost: { input: 0.4, output: 2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "moonshotai/Kimi-K2.5-TEE",
|
||||
name: "moonshotai/Kimi-K2.5-TEE",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65535,
|
||||
cost: { input: 0.45, output: 2.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/gemma-3-27b-it",
|
||||
name: "unsloth/gemma-3-27b-it",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 128000,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.04, output: 0.15, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "XiaomiMiMo/MiMo-V2-Flash-TEE",
|
||||
name: "XiaomiMiMo/MiMo-V2-Flash-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.09, output: 0.29, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
name: "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.06, output: 0.18, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-R1-0528-TEE",
|
||||
name: "deepseek-ai/DeepSeek-R1-0528-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.45, output: 2.15, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-5-TEE",
|
||||
name: "zai-org/GLM-5-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 202752,
|
||||
maxTokens: 65535,
|
||||
cost: { input: 0.95, output: 3.15, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3.1-TEE",
|
||||
name: "deepseek-ai/DeepSeek-V3.1-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.2, output: 0.8, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
|
||||
name: "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.23, output: 0.9, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/gemma-3-4b-it",
|
||||
name: "unsloth/gemma-3-4b-it",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 96000,
|
||||
maxTokens: 96000,
|
||||
cost: { input: 0.01, output: 0.03, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "MiniMaxAI/MiniMax-M2.5-TEE",
|
||||
name: "MiniMaxAI/MiniMax-M2.5-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 196608,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.3, output: 1.1, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "tngtech/DeepSeek-TNG-R1T2-Chimera",
|
||||
name: "tngtech/DeepSeek-TNG-R1T2-Chimera",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 163840,
|
||||
cost: { input: 0.25, output: 0.85, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-Coder-Next-TEE",
|
||||
name: "Qwen/Qwen3-Coder-Next-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.12, output: 0.75, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "NousResearch/Hermes-4-405B-FP8-TEE",
|
||||
name: "NousResearch/Hermes-4-405B-FP8-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-V3",
|
||||
name: "deepseek-ai/DeepSeek-V3",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 163840,
|
||||
maxTokens: 163840,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-oss-20b",
|
||||
name: "openai/gpt-oss-20b",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.04, output: 0.15, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/Llama-3.2-3B-Instruct",
|
||||
name: "unsloth/Llama-3.2-3B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4096,
|
||||
cost: { input: 0.01, output: 0.01, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/Mistral-Small-24B-Instruct-2501",
|
||||
name: "unsloth/Mistral-Small-24B-Instruct-2501",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 32768,
|
||||
maxTokens: 32768,
|
||||
cost: { input: 0.07, output: 0.3, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-4.7-FP8",
|
||||
name: "zai-org/GLM-4.7-FP8",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 202752,
|
||||
maxTokens: 65535,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-4.6-TEE",
|
||||
name: "zai-org/GLM-4.6-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 202752,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.4, output: 1.7, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3.5-397B-A17B-TEE",
|
||||
name: "Qwen/Qwen3.5-397B-A17B-TEE",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.55, output: 3.5, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen2.5-72B-Instruct",
|
||||
name: "Qwen/Qwen2.5-72B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 32768,
|
||||
maxTokens: 32768,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "NousResearch/DeepHermes-3-Mistral-24B-Preview",
|
||||
name: "NousResearch/DeepHermes-3-Mistral-24B-Preview",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 32768,
|
||||
maxTokens: 32768,
|
||||
cost: { input: 0.02, output: 0.1, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-Next-80B-A3B-Instruct",
|
||||
name: "Qwen/Qwen3-Next-80B-A3B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
cost: { input: 0.1, output: 0.8, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-4.6-FP8",
|
||||
name: "zai-org/GLM-4.6-FP8",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 202752,
|
||||
maxTokens: 65535,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
name: "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
cost: { input: 0.11, output: 0.6, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
||||
name: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.03, output: 0.11, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "tngtech/R1T2-Chimera-Speed",
|
||||
name: "tngtech/R1T2-Chimera-Speed",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.22, output: 0.6, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "zai-org/GLM-4.6V",
|
||||
name: "zai-org/GLM-4.6V",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 65536,
|
||||
cost: { input: 0.3, output: 0.9, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen2.5-VL-32B-Instruct",
|
||||
name: "Qwen/Qwen2.5-VL-32B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
mediaInput: {
|
||||
image: { maxPixels: 12845056, preferredSidePx: 2048, tokenMode: "provider" },
|
||||
},
|
||||
contextWindow: 16384,
|
||||
maxTokens: 16384,
|
||||
cost: { input: 0.05, output: 0.22, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-VL-235B-A22B-Instruct",
|
||||
name: "Qwen/Qwen3-VL-235B-A22B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
mediaInput: {
|
||||
image: { maxPixels: 12845056, preferredSidePx: 2048, tokenMode: "provider" },
|
||||
},
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-14B",
|
||||
name: "Qwen/Qwen3-14B",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 40960,
|
||||
maxTokens: 40960,
|
||||
cost: { input: 0.05, output: 0.22, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen2.5-Coder-32B-Instruct",
|
||||
name: "Qwen/Qwen2.5-Coder-32B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 32768,
|
||||
maxTokens: 32768,
|
||||
cost: { input: 0.03, output: 0.11, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3-30B-A3B",
|
||||
name: "Qwen/Qwen3-30B-A3B",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 40960,
|
||||
maxTokens: 40960,
|
||||
cost: { input: 0.06, output: 0.22, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/gemma-3-12b-it",
|
||||
name: "unsloth/gemma-3-12b-it",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.03, output: 0.1, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "unsloth/Llama-3.2-1B-Instruct",
|
||||
name: "unsloth/Llama-3.2-1B-Instruct",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4096,
|
||||
cost: { input: 0.01, output: 0.01, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
|
||||
name: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4096,
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "NousResearch/Hermes-4-14B",
|
||||
name: "NousResearch/Hermes-4-14B",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
contextWindow: 40960,
|
||||
maxTokens: 40960,
|
||||
cost: { input: 0.01, output: 0.05, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "Qwen/Qwen3Guard-Gen-0.6B",
|
||||
name: "Qwen/Qwen3Guard-Gen-0.6B",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 128000,
|
||||
maxTokens: 4096,
|
||||
cost: { input: 0.01, output: 0.01, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
{
|
||||
id: "rednote-hilab/dots.ocr",
|
||||
name: "rednote-hilab/dots.ocr",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 131072,
|
||||
cost: { input: 0.01, output: 0.01, cacheRead: 0, cacheWrite: 0 },
|
||||
},
|
||||
];
|
||||
/** Bundled fallback Chutes model catalog, normalized from the plugin manifest. */
|
||||
export const CHUTES_MODEL_CATALOG = CHUTES_MANIFEST_PROVIDER.models;
|
||||
|
||||
/** Adds Chutes provider compat metadata to one model catalog entry. */
|
||||
export function buildChutesModelDefinition(
|
||||
model: (typeof CHUTES_MODEL_CATALOG)[number],
|
||||
): ModelDefinitionConfig {
|
||||
export function buildChutesModelDefinition(model: ModelDefinitionConfig): ModelDefinitionConfig {
|
||||
return {
|
||||
...model,
|
||||
compat: {
|
||||
...model.compat,
|
||||
supportsUsageInStreaming: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ export { CHUTES_DEFAULT_MODEL_REF };
|
||||
|
||||
/**
|
||||
* Apply Chutes provider configuration without changing the default model.
|
||||
* Registers all catalog models and sets provider aliases (chutes-fast, etc.).
|
||||
* Registers all catalog models and convenience aliases.
|
||||
*/
|
||||
export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||
@@ -27,10 +27,9 @@ export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
catalogModels: CHUTES_MODEL_CATALOG.map(buildChutesModelDefinition),
|
||||
aliases: [
|
||||
...CHUTES_MODEL_CATALOG.map((model) => `chutes/${model.id}`),
|
||||
{ modelRef: "chutes-fast", alias: "chutes/zai-org/GLM-4.7-FP8" },
|
||||
{
|
||||
modelRef: "chutes-vision",
|
||||
alias: "chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
alias: "chutes/moonshotai/Kimi-K2.5-TEE",
|
||||
},
|
||||
{ modelRef: "chutes-pro", alias: "chutes/deepseek-ai/DeepSeek-V3.2-TEE" },
|
||||
],
|
||||
@@ -50,11 +49,11 @@ export function applyChutesConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
...next.agents?.defaults,
|
||||
model: {
|
||||
primary: CHUTES_DEFAULT_MODEL_REF,
|
||||
fallbacks: ["chutes/deepseek-ai/DeepSeek-V3.2-TEE", "chutes/Qwen/Qwen3-32B"],
|
||||
fallbacks: ["chutes/deepseek-ai/DeepSeek-V3.2-TEE", "chutes/moonshotai/Kimi-K2.5-TEE"],
|
||||
},
|
||||
imageModel: {
|
||||
primary: "chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
fallbacks: ["chutes/chutesai/Mistral-Small-3.1-24B-Instruct-2503"],
|
||||
primary: "chutes/moonshotai/Kimi-K2.5-TEE",
|
||||
fallbacks: ["chutes/Qwen/Qwen3.5-397B-A17B-TEE"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -65,90 +65,6 @@
|
||||
"baseUrl": "https://llm.chutes.ai/v1",
|
||||
"api": "openai-completions",
|
||||
"models": [
|
||||
{
|
||||
"id": "Qwen/Qwen3-32B",
|
||||
"name": "Qwen/Qwen3-32B",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 40960,
|
||||
"maxTokens": 40960,
|
||||
"cost": {
|
||||
"input": 0.08,
|
||||
"output": 0.24,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
"name": "unsloth/Mistral-Nemo-Instruct-2407",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.02,
|
||||
"output": 0.04,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
"name": "deepseek-ai/DeepSeek-V3-0324-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.25,
|
||||
"output": 1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
|
||||
"name": "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.08,
|
||||
"output": 0.55,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "openai/gpt-oss-120b-TEE",
|
||||
"name": "openai/gpt-oss-120b-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.05,
|
||||
"output": 0.45,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
|
||||
"name": "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.03,
|
||||
"output": 0.11,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
"name": "deepseek-ai/DeepSeek-V3.2-TEE",
|
||||
@@ -157,23 +73,9 @@
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.28,
|
||||
"output": 0.42,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zai-org/GLM-4.7-TEE",
|
||||
"name": "zai-org/GLM-4.7-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65535,
|
||||
"cost": {
|
||||
"input": 0.4,
|
||||
"output": 2,
|
||||
"cacheRead": 0,
|
||||
"input": 1,
|
||||
"output": 1,
|
||||
"cacheRead": 0.5,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
@@ -185,65 +87,9 @@
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65535,
|
||||
"cost": {
|
||||
"input": 0.45,
|
||||
"output": 2.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/gemma-3-27b-it",
|
||||
"name": "unsloth/gemma-3-27b-it",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.04,
|
||||
"output": 0.15,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "XiaomiMiMo/MiMo-V2-Flash-TEE",
|
||||
"name": "XiaomiMiMo/MiMo-V2-Flash-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.09,
|
||||
"output": 0.29,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
"name": "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.06,
|
||||
"output": 0.18,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-R1-0528-TEE",
|
||||
"name": "deepseek-ai/DeepSeek-R1-0528-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.45,
|
||||
"output": 2.15,
|
||||
"cacheRead": 0,
|
||||
"input": 0.44,
|
||||
"output": 2,
|
||||
"cacheRead": 0.22,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
@@ -256,50 +102,8 @@
|
||||
"maxTokens": 65535,
|
||||
"cost": {
|
||||
"input": 0.95,
|
||||
"output": 3.15,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3.1-TEE",
|
||||
"name": "deepseek-ai/DeepSeek-V3.1-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.2,
|
||||
"output": 0.8,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
|
||||
"name": "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.23,
|
||||
"output": 0.9,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/gemma-3-4b-it",
|
||||
"name": "unsloth/gemma-3-4b-it",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 96000,
|
||||
"maxTokens": 96000,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.03,
|
||||
"cacheRead": 0,
|
||||
"output": 2.55,
|
||||
"cacheRead": 0.475,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
@@ -311,135 +115,9 @@
|
||||
"contextWindow": 196608,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tngtech/DeepSeek-TNG-R1T2-Chimera",
|
||||
"name": "tngtech/DeepSeek-TNG-R1T2-Chimera",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 163840,
|
||||
"cost": {
|
||||
"input": 0.25,
|
||||
"output": 0.85,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-Coder-Next-TEE",
|
||||
"name": "Qwen/Qwen3-Coder-Next-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.12,
|
||||
"output": 0.75,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "NousResearch/Hermes-4-405B-FP8-TEE",
|
||||
"name": "NousResearch/Hermes-4-405B-FP8-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"input": 0.15,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-V3",
|
||||
"name": "deepseek-ai/DeepSeek-V3",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 163840,
|
||||
"maxTokens": 163840,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "openai/gpt-oss-20b",
|
||||
"name": "openai/gpt-oss-20b",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.04,
|
||||
"output": 0.15,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/Llama-3.2-3B-Instruct",
|
||||
"name": "unsloth/Llama-3.2-3B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 4096,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.01,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/Mistral-Small-24B-Instruct-2501",
|
||||
"name": "unsloth/Mistral-Small-24B-Instruct-2501",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 32768,
|
||||
"maxTokens": 32768,
|
||||
"cost": {
|
||||
"input": 0.07,
|
||||
"output": 0.3,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zai-org/GLM-4.7-FP8",
|
||||
"name": "zai-org/GLM-4.7-FP8",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65535,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zai-org/GLM-4.6-TEE",
|
||||
"name": "zai-org/GLM-4.6-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.4,
|
||||
"output": 1.7,
|
||||
"cacheRead": 0,
|
||||
"cacheRead": 0.075,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
@@ -451,281 +129,9 @@
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.55,
|
||||
"output": 3.5,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen2.5-72B-Instruct",
|
||||
"name": "Qwen/Qwen2.5-72B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 32768,
|
||||
"maxTokens": 32768,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "NousResearch/DeepHermes-3-Mistral-24B-Preview",
|
||||
"name": "NousResearch/DeepHermes-3-Mistral-24B-Preview",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 32768,
|
||||
"maxTokens": 32768,
|
||||
"cost": {
|
||||
"input": 0.02,
|
||||
"output": 0.1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-Next-80B-A3B-Instruct",
|
||||
"name": "Qwen/Qwen3-Next-80B-A3B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 0.1,
|
||||
"output": 0.8,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zai-org/GLM-4.6-FP8",
|
||||
"name": "zai-org/GLM-4.6-FP8",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65535,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
"name": "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 0.11,
|
||||
"output": 0.6,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
||||
"name": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.03,
|
||||
"output": 0.11,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tngtech/R1T2-Chimera-Speed",
|
||||
"name": "tngtech/R1T2-Chimera-Speed",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.22,
|
||||
"output": 0.6,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "zai-org/GLM-4.6V",
|
||||
"name": "zai-org/GLM-4.6V",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 65536,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 0.9,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen2.5-VL-32B-Instruct",
|
||||
"name": "Qwen/Qwen2.5-VL-32B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"mediaInput": {
|
||||
"image": { "maxPixels": 12845056, "preferredSidePx": 2048, "tokenMode": "provider" }
|
||||
},
|
||||
"contextWindow": 16384,
|
||||
"maxTokens": 16384,
|
||||
"cost": {
|
||||
"input": 0.05,
|
||||
"output": 0.22,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-VL-235B-A22B-Instruct",
|
||||
"name": "Qwen/Qwen3-VL-235B-A22B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"mediaInput": {
|
||||
"image": { "maxPixels": 12845056, "preferredSidePx": 2048, "tokenMode": "provider" }
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-14B",
|
||||
"name": "Qwen/Qwen3-14B",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 40960,
|
||||
"maxTokens": 40960,
|
||||
"cost": {
|
||||
"input": 0.05,
|
||||
"output": 0.22,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen2.5-Coder-32B-Instruct",
|
||||
"name": "Qwen/Qwen2.5-Coder-32B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 32768,
|
||||
"maxTokens": 32768,
|
||||
"cost": {
|
||||
"input": 0.03,
|
||||
"output": 0.11,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3-30B-A3B",
|
||||
"name": "Qwen/Qwen3-30B-A3B",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 40960,
|
||||
"maxTokens": 40960,
|
||||
"cost": {
|
||||
"input": 0.06,
|
||||
"output": 0.22,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/gemma-3-12b-it",
|
||||
"name": "unsloth/gemma-3-12b-it",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.03,
|
||||
"output": 0.1,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "unsloth/Llama-3.2-1B-Instruct",
|
||||
"name": "unsloth/Llama-3.2-1B-Instruct",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 4096,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.01,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
|
||||
"name": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 4096,
|
||||
"cost": {
|
||||
"input": 0.3,
|
||||
"output": 1.2,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "NousResearch/Hermes-4-14B",
|
||||
"name": "NousResearch/Hermes-4-14B",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 40960,
|
||||
"maxTokens": 40960,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.05,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Qwen/Qwen3Guard-Gen-0.6B",
|
||||
"name": "Qwen/Qwen3Guard-Gen-0.6B",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 4096,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.01,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rednote-hilab/dots.ocr",
|
||||
"name": "rednote-hilab/dots.ocr",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 131072,
|
||||
"maxTokens": 131072,
|
||||
"cost": {
|
||||
"input": 0.01,
|
||||
"output": 0.01,
|
||||
"cacheRead": 0,
|
||||
"input": 0.45,
|
||||
"output": 3,
|
||||
"cacheRead": 0.225,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,10 @@ const DEFAULT_API_KEY = "n/a";
|
||||
const DEFAULT_CONTEXT_WINDOW = 128_000;
|
||||
const DEFAULT_MAX_TOKENS = 8192;
|
||||
const DEFAULT_MODEL_IDS = [
|
||||
"gpt-5.2",
|
||||
"gpt-5.2-codex",
|
||||
"gpt-5.1",
|
||||
"gpt-5.1-codex",
|
||||
"gpt-5.1-codex-max",
|
||||
"gpt-5-mini",
|
||||
"claude-opus-4.6",
|
||||
"claude-opus-4.7",
|
||||
"claude-sonnet-4.6",
|
||||
"gemini-3-pro",
|
||||
"gemini-3-flash",
|
||||
] as const;
|
||||
|
||||
|
||||
@@ -90,6 +90,12 @@ describe("deepinfra image generation provider", () => {
|
||||
|
||||
expect(provider.id).toBe("deepinfra");
|
||||
expect(provider.defaultModel).toBe("black-forest-labs/FLUX-1-schnell");
|
||||
expect(provider.models).toEqual([
|
||||
"black-forest-labs/FLUX-1-schnell",
|
||||
"black-forest-labs/FLUX-1-dev",
|
||||
"Qwen/Qwen-Image-Max",
|
||||
"stabilityai/sdxl-turbo",
|
||||
]);
|
||||
expect(provider.capabilities.generate.maxCount).toBe(4);
|
||||
expect(provider.capabilities.edit.enabled).toBe(true);
|
||||
expect(provider.capabilities.edit.maxInputImages).toBe(1);
|
||||
|
||||
@@ -16,7 +16,6 @@ export const DEEPINFRA_VIDEO_DURATIONS = [5, 8] as const;
|
||||
// supplied. First entry is the default. Prefer discoverDeepInfraSurfaces().
|
||||
export const DEEPINFRA_IMAGE_FALLBACK_MODELS = [
|
||||
"black-forest-labs/FLUX-1-schnell",
|
||||
"run-diffusion/Juggernaut-Lightning-Flux",
|
||||
"black-forest-labs/FLUX-1-dev",
|
||||
"Qwen/Qwen-Image-Max",
|
||||
"stabilityai/sdxl-turbo",
|
||||
|
||||
@@ -164,7 +164,7 @@ describe("fireworks provider plugin", () => {
|
||||
expect(
|
||||
provider.resolveThinkingProfile?.({
|
||||
provider: "fireworks",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
modelId: FIREWORKS_DEFAULT_MODEL_ID,
|
||||
}),
|
||||
).toEqual({
|
||||
levels: [{ id: "off" }],
|
||||
|
||||
@@ -21,7 +21,7 @@ const fireworksPresetAppliers = createDefaultModelsPresetAppliers({
|
||||
baseUrl: defaultProvider.baseUrl,
|
||||
defaultModels: buildFireworksCatalogModels(),
|
||||
defaultModelId: FIREWORKS_DEFAULT_MODEL_ID,
|
||||
aliases: [{ modelRef: FIREWORKS_DEFAULT_MODEL_REF, alias: "Kimi K2.5 Turbo" }],
|
||||
aliases: [{ modelRef: FIREWORKS_DEFAULT_MODEL_REF, alias: "Kimi K2.6 Turbo" }],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
"name": "Kimi K2.5 Turbo (Fire Pass)",
|
||||
"id": "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
"name": "Kimi K2.6 Turbo (Fire Pass)",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 256000,
|
||||
|
||||
@@ -12,7 +12,7 @@ const FIREWORKS_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
|
||||
});
|
||||
|
||||
export const FIREWORKS_BASE_URL = FIREWORKS_MANIFEST_PROVIDER.baseUrl;
|
||||
export const FIREWORKS_DEFAULT_MODEL_ID = "accounts/fireworks/routers/kimi-k2p5-turbo";
|
||||
export const FIREWORKS_DEFAULT_MODEL_ID = "accounts/fireworks/routers/kimi-k2p6-turbo";
|
||||
|
||||
function requireFireworksManifestModel(id: string): ModelDefinitionConfig {
|
||||
const model = FIREWORKS_MANIFEST_PROVIDER.models.find((entry) => entry.id === id);
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("createFireworksKimiThinkingDisabledWrapper", () => {
|
||||
capturePayload({
|
||||
provider: "fireworks",
|
||||
api: "openai-completions",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
}),
|
||||
).toEqual({ thinking: { type: "disabled" } });
|
||||
});
|
||||
@@ -116,7 +116,7 @@ describe("createFireworksKimiThinkingDisabledWrapper", () => {
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "fireworks",
|
||||
id: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
id: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
} as Model<"openai-completions">;
|
||||
const wrapped = wrapFireworksProviderStream({
|
||||
provider: "fireworks",
|
||||
@@ -153,11 +153,11 @@ describe("createFireworksKimiThinkingDisabledWrapper", () => {
|
||||
expect(
|
||||
wrapFireworksProviderStream({
|
||||
provider: "fireworks",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
model: {
|
||||
api: "openai-responses",
|
||||
provider: "fireworks",
|
||||
id: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
id: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
} as Model<"openai-responses">,
|
||||
streamFn: undefined,
|
||||
} as never),
|
||||
@@ -166,11 +166,11 @@ describe("createFireworksKimiThinkingDisabledWrapper", () => {
|
||||
expect(
|
||||
wrapFireworksProviderStream({
|
||||
provider: "fireworks-ai",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
modelId: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
model: {
|
||||
api: "openai-completions",
|
||||
provider: "fireworks-ai",
|
||||
id: "accounts/fireworks/routers/kimi-k2p5-turbo",
|
||||
id: "accounts/fireworks/routers/kimi-k2p6-turbo",
|
||||
} as Model<"openai-completions">,
|
||||
streamFn: undefined,
|
||||
} as never),
|
||||
|
||||
@@ -121,15 +121,6 @@
|
||||
"maxTokens": 8192,
|
||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.4-nano",
|
||||
"name": "GPT-5.4 nano",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 128000,
|
||||
"maxTokens": 8192,
|
||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
||||
},
|
||||
{
|
||||
"id": "raptor-mini",
|
||||
"name": "Raptor mini",
|
||||
|
||||
@@ -71,8 +71,8 @@ function makeGeminiClient(
|
||||
): GeminiEmbeddingClient {
|
||||
return {
|
||||
baseUrl,
|
||||
model: "text-embedding-004",
|
||||
modelPath: "models/text-embedding-004",
|
||||
model: "gemini-embedding-001",
|
||||
modelPath: "models/gemini-embedding-001",
|
||||
headers: { "x-goog-api-client": "test-client" },
|
||||
apiKeys: ["test-key"],
|
||||
ssrfPolicy: undefined,
|
||||
@@ -85,7 +85,7 @@ function batchRequest(customId: string, text: string): GeminiBatchRequest {
|
||||
return {
|
||||
custom_id: customId,
|
||||
request: {
|
||||
model: "models/text-embedding-004",
|
||||
model: "models/gemini-embedding-001",
|
||||
content: { parts: [{ text }] },
|
||||
taskType: "RETRIEVAL_DOCUMENT",
|
||||
},
|
||||
|
||||
@@ -41,7 +41,6 @@ export type GeminiEmbeddingClient = {
|
||||
export const DEFAULT_GEMINI_EMBEDDING_MODEL = "gemini-embedding-001";
|
||||
const DEFAULT_GOOGLE_API_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
||||
const GEMINI_MAX_INPUT_TOKENS: Record<string, number> = {
|
||||
"text-embedding-004": 2048,
|
||||
"gemini-embedding-001": 2048,
|
||||
"gemini-embedding-2-preview": 8192,
|
||||
};
|
||||
|
||||
@@ -73,9 +73,6 @@ export function createGoogleVideoGenerationProviderMetadata(): Omit<
|
||||
DEFAULT_GOOGLE_VIDEO_MODEL,
|
||||
"veo-3.1-generate-preview",
|
||||
"veo-3.1-lite-generate-preview",
|
||||
"veo-3.0-fast-generate-001",
|
||||
"veo-3.0-generate-001",
|
||||
"veo-2.0-generate-001",
|
||||
],
|
||||
isConfigured: isGoogleProviderConfigured,
|
||||
capabilities: {
|
||||
|
||||
@@ -130,7 +130,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
size: "1536x1024",
|
||||
@@ -138,7 +138,7 @@ describe("Google image-generation provider", () => {
|
||||
|
||||
const request = fetchRequest(fetchMock);
|
||||
expect(request.url).toBe(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image:generateContent",
|
||||
);
|
||||
expect(request.method).toBe("POST");
|
||||
expect(JSON.parse(request.body ?? "")).toEqual({
|
||||
@@ -164,7 +164,7 @@ describe("Google image-generation provider", () => {
|
||||
fileName: "image-1.png",
|
||||
},
|
||||
],
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,14 +191,14 @@ describe("Google image-generation provider", () => {
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
finalUrl:
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image:generateContent",
|
||||
release: async () => {},
|
||||
});
|
||||
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
ssrfPolicy: { allowRfc2544BenchmarkRange: true },
|
||||
@@ -220,7 +220,7 @@ describe("Google image-generation provider", () => {
|
||||
await expect(
|
||||
provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -248,7 +248,7 @@ describe("Google image-generation provider", () => {
|
||||
await expect(
|
||||
provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -284,7 +284,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a dog",
|
||||
cfg: {},
|
||||
});
|
||||
@@ -301,7 +301,7 @@ describe("Google image-generation provider", () => {
|
||||
fileName: "image-1.jpg",
|
||||
},
|
||||
],
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -332,7 +332,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
});
|
||||
@@ -366,7 +366,7 @@ describe("Google image-generation provider", () => {
|
||||
await expect(
|
||||
provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
}),
|
||||
@@ -380,7 +380,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3-pro-image-preview",
|
||||
model: "gemini-3-pro-image",
|
||||
prompt: "Change only the sky to a sunset.",
|
||||
cfg: {},
|
||||
resolution: "4K",
|
||||
@@ -395,7 +395,7 @@ describe("Google image-generation provider", () => {
|
||||
|
||||
const request = fetchRequest(fetchMock);
|
||||
expect(request.url).toBe(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent",
|
||||
);
|
||||
expect(request.method).toBe("POST");
|
||||
expect(JSON.parse(request.body ?? "")).toEqual({
|
||||
@@ -429,7 +429,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3-pro-image-preview",
|
||||
model: "gemini-3-pro-image",
|
||||
prompt: "portrait photo",
|
||||
cfg: {},
|
||||
aspectRatio: "9:16",
|
||||
@@ -437,7 +437,7 @@ describe("Google image-generation provider", () => {
|
||||
|
||||
const request = fetchRequest(fetchMock);
|
||||
expect(request.url).toBe(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent",
|
||||
);
|
||||
expect(request.method).toBe("POST");
|
||||
expect(JSON.parse(request.body ?? "")).toEqual({
|
||||
@@ -464,7 +464,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a fox",
|
||||
cfg: {},
|
||||
});
|
||||
@@ -480,7 +480,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-image-preview",
|
||||
model: "gemini-3.1-flash-image",
|
||||
prompt: "draw a fox",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -505,7 +505,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3-pro-image-preview",
|
||||
model: "gemini-3-pro-image",
|
||||
prompt: "draw a cat",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -521,7 +521,7 @@ describe("Google image-generation provider", () => {
|
||||
|
||||
const request = fetchRequest(fetchMock);
|
||||
expect(request.url).toBe(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent",
|
||||
);
|
||||
expect(typeof request.method).toBe("string");
|
||||
});
|
||||
@@ -533,7 +533,7 @@ describe("Google image-generation provider", () => {
|
||||
const provider = buildGoogleImageGenerationProvider();
|
||||
await provider.generateImage({
|
||||
provider: "google",
|
||||
model: "gemini-3-pro-image-preview",
|
||||
model: "gemini-3-pro-image",
|
||||
prompt: "draw a fox",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -549,7 +549,7 @@ describe("Google image-generation provider", () => {
|
||||
|
||||
const request = fetchRequest(fetchMock);
|
||||
expect(request.url).toBe(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:generateContent",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image:generateContent",
|
||||
);
|
||||
expect(typeof request.method).toBe("string");
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { normalizeGoogleModelId, resolveGoogleGenerativeAiHttpRequestConfig } from "./api.js";
|
||||
|
||||
const DEFAULT_GOOGLE_IMAGE_MODEL = "gemini-3.1-flash-image-preview";
|
||||
const DEFAULT_GOOGLE_IMAGE_MODEL = "gemini-3.1-flash-image";
|
||||
const DEFAULT_IMAGE_TIMEOUT_MS = 180_000;
|
||||
const DEFAULT_OUTPUT_MIME = "image/png";
|
||||
const GOOGLE_MAX_IMAGE_RESULTS = 4;
|
||||
@@ -159,7 +159,7 @@ export function buildGoogleImageGenerationProvider(): ImageGenerationProvider {
|
||||
id: "google",
|
||||
label: "Google",
|
||||
defaultModel: DEFAULT_GOOGLE_IMAGE_MODEL,
|
||||
models: [DEFAULT_GOOGLE_IMAGE_MODEL, "gemini-3-pro-image-preview"],
|
||||
models: [DEFAULT_GOOGLE_IMAGE_MODEL, "gemini-3-pro-image"],
|
||||
isConfigured: ({ cfg, agentDir }) =>
|
||||
// generateImage already authenticates from a config apiKey; count a
|
||||
// usable one (non-blank literal or secret ref) as configured here too,
|
||||
|
||||
@@ -98,8 +98,8 @@ function createLazyGoogleImageGenerationProvider(): ImageGenerationProvider {
|
||||
return {
|
||||
id: "google",
|
||||
label: "Google",
|
||||
defaultModel: "gemini-3.1-flash-image-preview",
|
||||
models: ["gemini-3.1-flash-image-preview", "gemini-3-pro-image-preview"],
|
||||
defaultModel: "gemini-3.1-flash-image",
|
||||
models: ["gemini-3.1-flash-image", "gemini-3-pro-image"],
|
||||
capabilities: {
|
||||
generate: {
|
||||
maxCount: 4,
|
||||
|
||||
@@ -24,9 +24,13 @@ const RETIRED_GEMINI_CHAT_MODELS = [
|
||||
"gemini-1.5-flash",
|
||||
"gemini-1.5-flash-8b",
|
||||
"gemini-1.5-pro",
|
||||
"gemini-2.0-flash",
|
||||
"gemini-2.0-flash-001",
|
||||
"gemini-2.0-flash-exp",
|
||||
"gemini-2.0-flash-exp-image-generation",
|
||||
"gemini-2.0-flash-live-001",
|
||||
"gemini-2.0-flash-lite",
|
||||
"gemini-2.0-flash-lite-001",
|
||||
"gemini-2.0-flash-lite-preview",
|
||||
"gemini-2.0-flash-lite-preview-02-05",
|
||||
"gemini-2.0-flash-preview-image-generation",
|
||||
@@ -86,7 +90,6 @@ describe("google manifest model catalog", () => {
|
||||
),
|
||||
);
|
||||
|
||||
expect(suppressionRefs).not.toContain("google/gemini-2.0-flash");
|
||||
expect(suppressionRefs).not.toContain("google/gemini-2.5-flash");
|
||||
expect(suppressionRefs).not.toContain("google/gemini-2.5-flash-lite");
|
||||
expect(suppressionRefs).not.toContain("google/gemini-2.5-pro");
|
||||
|
||||
@@ -62,6 +62,16 @@
|
||||
"model": "gemini-1.5-pro",
|
||||
"reason": "Google shut down Gemini 1.5 Pro on 2025-09-29. Use google/gemini-3.1-pro-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash-exp",
|
||||
@@ -77,6 +87,16 @@
|
||||
"model": "gemini-2.0-flash-live-001",
|
||||
"reason": "Google shut down this Gemini Live model on 2025-12-09. Use google/gemini-3.1-flash-live-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash-lite",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash-lite-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google",
|
||||
"model": "gemini-2.0-flash-lite-preview",
|
||||
@@ -227,6 +247,16 @@
|
||||
"model": "gemini-1.5-pro",
|
||||
"reason": "Google shut down Gemini 1.5 Pro on 2025-09-29. Use google-gemini-cli/gemini-3.1-pro-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google-gemini-cli/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google-gemini-cli/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash-exp",
|
||||
@@ -242,6 +272,16 @@
|
||||
"model": "gemini-2.0-flash-live-001",
|
||||
"reason": "Google shut down this Gemini Live model on 2025-12-09. Use google-gemini-cli/gemini-3.1-flash-live-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash-lite",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google-gemini-cli/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash-lite-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google-gemini-cli/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google-gemini-cli",
|
||||
"model": "gemini-2.0-flash-lite-preview",
|
||||
@@ -392,6 +432,16 @@
|
||||
"model": "gemini-1.5-pro",
|
||||
"reason": "Google retired Gemini 1.5 Pro. Use google-vertex/gemini-3.1-pro-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google-vertex/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash on 2026-06-01. Use google-vertex/gemini-2.5-flash."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash-exp",
|
||||
@@ -407,6 +457,16 @@
|
||||
"model": "gemini-2.0-flash-live-001",
|
||||
"reason": "Google shut down this Gemini Live model on 2025-12-09. Use google-vertex/gemini-3.1-flash-live-preview."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash-lite",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google-vertex/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash-lite-001",
|
||||
"reason": "Google shut down Gemini 2.0 Flash-Lite on 2026-06-01. Use google-vertex/gemini-2.5-flash-lite."
|
||||
},
|
||||
{
|
||||
"provider": "google-vertex",
|
||||
"model": "gemini-2.0-flash-lite-preview",
|
||||
|
||||
@@ -54,6 +54,12 @@ describe("huggingface models", () => {
|
||||
expect(def.maxTokens).toBe(entry.maxTokens);
|
||||
});
|
||||
|
||||
it("does not advertise the retired Llama 3.3 Turbo route", () => {
|
||||
expect(HUGGINGFACE_MODEL_CATALOG.map((model) => model.id)).not.toContain(
|
||||
"meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
||||
);
|
||||
});
|
||||
|
||||
it("discoverHuggingfaceModels returns static catalog when apiKey is empty", async () => {
|
||||
const models = await discoverHuggingfaceModels("");
|
||||
expect(models).toHaveLength(HUGGINGFACE_MODEL_CATALOG.length);
|
||||
|
||||
@@ -60,15 +60,6 @@ export const HUGGINGFACE_MODEL_CATALOG: ModelDefinitionConfig[] = [
|
||||
maxTokens: 8192,
|
||||
cost: { input: 0.6, output: 1.25, cacheRead: 0.6, cacheWrite: 0.6 },
|
||||
},
|
||||
{
|
||||
id: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
||||
name: "Llama 3.3 70B Instruct Turbo",
|
||||
reasoning: false,
|
||||
input: ["text"],
|
||||
contextWindow: 131072,
|
||||
maxTokens: 8192,
|
||||
cost: { input: 0.88, output: 0.88, cacheRead: 0.88, cacheWrite: 0.88 },
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-oss-120b",
|
||||
name: "GPT-OSS 120B",
|
||||
|
||||
@@ -10,13 +10,13 @@ describe("Kilo Gateway implicit provider", () => {
|
||||
expect(provider.api).toBe("openai-completions");
|
||||
expect(provider.models).toStrictEqual([
|
||||
{
|
||||
id: "kilo/auto",
|
||||
name: "Kilo Auto",
|
||||
id: "kilo-auto/balanced",
|
||||
name: "Auto Balanced",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
cost: { input: 0.325, output: 1.95, cacheRead: 0.0325, cacheWrite: 0.40625 },
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
maxTokens: 65536,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ describe("kilocode provider plugin", () => {
|
||||
|
||||
const wrappedAuto = provider.wrapStreamFn?.({
|
||||
provider: "kilocode",
|
||||
modelId: "kilo/auto",
|
||||
modelId: "kilo-auto/balanced",
|
||||
thinkingLevel: "high",
|
||||
streamFn: baseStreamFn,
|
||||
} as never);
|
||||
@@ -62,7 +62,7 @@ describe("kilocode provider plugin", () => {
|
||||
{
|
||||
api: "openai-completions",
|
||||
provider: "kilocode",
|
||||
id: "kilo/auto",
|
||||
id: "kilo-auto/balanced",
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{},
|
||||
|
||||
@@ -14,7 +14,7 @@ import { applyKilocodeConfig, KILOCODE_DEFAULT_MODEL_REF } from "./onboard.js";
|
||||
import { KILOCODE_BASE_URL } from "./provider-models.js";
|
||||
|
||||
const emptyCfg: OpenClawConfig = {};
|
||||
const KILOCODE_MODEL_IDS = ["kilo/auto"];
|
||||
const KILOCODE_MODEL_IDS = ["kilo-auto/balanced"];
|
||||
|
||||
function requireKilocodeProvider(cfg: OpenClawConfig) {
|
||||
const provider = cfg.models?.providers?.kilocode;
|
||||
@@ -31,11 +31,11 @@ describe("Kilo Gateway provider config", () => {
|
||||
});
|
||||
|
||||
it("KILOCODE_DEFAULT_MODEL_REF includes provider prefix", () => {
|
||||
expect(KILOCODE_DEFAULT_MODEL_REF).toBe("kilocode/kilo/auto");
|
||||
expect(KILOCODE_DEFAULT_MODEL_REF).toBe("kilocode/kilo-auto/balanced");
|
||||
});
|
||||
|
||||
it("KILOCODE_DEFAULT_MODEL_ID is kilo/auto", () => {
|
||||
expect(KILOCODE_DEFAULT_MODEL_ID).toBe("kilo/auto");
|
||||
it("KILOCODE_DEFAULT_MODEL_ID is kilo-auto/balanced", () => {
|
||||
expect(KILOCODE_DEFAULT_MODEL_ID).toBe("kilo-auto/balanced");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("Kilo Gateway provider config", () => {
|
||||
it("returns correct model shape", () => {
|
||||
const model = buildKilocodeModelDefinition();
|
||||
expect(model.id).toBe(KILOCODE_DEFAULT_MODEL_ID);
|
||||
expect(model.name).toBe("Kilo Auto");
|
||||
expect(model.name).toBe("Auto Balanced");
|
||||
expect(model.reasoning).toBe(true);
|
||||
expect(model.input).toEqual(["text", "image"]);
|
||||
expect(model.contextWindow).toBe(KILOCODE_DEFAULT_CONTEXT_WINDOW);
|
||||
|
||||
@@ -54,18 +54,18 @@
|
||||
"api": "openai-completions",
|
||||
"models": [
|
||||
{
|
||||
"id": "kilo/auto",
|
||||
"name": "Kilo Auto",
|
||||
"id": "kilo-auto/balanced",
|
||||
"name": "Auto Balanced",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
"input": 0.325,
|
||||
"output": 1.95,
|
||||
"cacheRead": 0.0325,
|
||||
"cacheWrite": 0.40625
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 128000
|
||||
"maxTokens": 65536
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ type MockKilocodeFetch = ((url: string, init?: RequestInit) => Promise<Response>
|
||||
|
||||
const EXPECTED_STATIC_KILOCODE_MODELS = [
|
||||
{
|
||||
id: "kilo/auto",
|
||||
name: "Kilo Auto",
|
||||
id: "kilo-auto/balanced",
|
||||
name: "Auto Balanced",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
cost: { input: 0.325, output: 1.95, cacheRead: 0.0325, cacheWrite: 0.40625 },
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
maxTokens: 65536,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -85,8 +85,8 @@ function makeGatewayModel(overrides: Record<string, unknown> = {}) {
|
||||
|
||||
function makeAutoModel(overrides: Record<string, unknown> = {}) {
|
||||
return makeGatewayModel({
|
||||
id: "kilo/auto",
|
||||
name: "Kilo: Auto",
|
||||
id: "kilo-auto/balanced",
|
||||
name: "Auto Balanced",
|
||||
context_length: 1000000,
|
||||
architecture: {
|
||||
input_modalities: ["text", "image"],
|
||||
@@ -95,11 +95,13 @@ function makeAutoModel(overrides: Record<string, unknown> = {}) {
|
||||
},
|
||||
top_provider: {
|
||||
is_moderated: false,
|
||||
max_completion_tokens: 128000,
|
||||
max_completion_tokens: 65536,
|
||||
},
|
||||
pricing: {
|
||||
prompt: "0.000005",
|
||||
completion: "0.000025",
|
||||
prompt: "0.000000325",
|
||||
completion: "0.00000195",
|
||||
input_cache_read: "0.0000000325",
|
||||
input_cache_write: "0.00000040625",
|
||||
},
|
||||
supported_parameters: ["max_tokens", "temperature", "tools", "reasoning", "include_reasoning"],
|
||||
...overrides,
|
||||
@@ -150,15 +152,20 @@ describe("discoverKilocodeModels", () => {
|
||||
expect(models).toStrictEqual(EXPECTED_STATIC_KILOCODE_MODELS);
|
||||
});
|
||||
|
||||
it("static catalog has correct defaults for kilo/auto", async () => {
|
||||
it("static catalog has correct defaults for kilo-auto/balanced", async () => {
|
||||
const models = await discoverKilocodeModels();
|
||||
const auto = requireModelById(models, "kilo/auto");
|
||||
expect(auto.name).toBe("Kilo Auto");
|
||||
const auto = requireModelById(models, "kilo-auto/balanced");
|
||||
expect(auto.name).toBe("Auto Balanced");
|
||||
expect(auto.reasoning).toBe(true);
|
||||
expect(auto.input).toEqual(["text", "image"]);
|
||||
expect(auto.contextWindow).toBe(1000000);
|
||||
expect(auto.maxTokens).toBe(128000);
|
||||
expect(auto.cost).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
|
||||
expect(auto.maxTokens).toBe(65536);
|
||||
expect(auto.cost).toEqual({
|
||||
input: 0.325,
|
||||
output: 1.95,
|
||||
cacheRead: 0.0325,
|
||||
cacheWrite: 0.40625,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -254,16 +261,16 @@ describe("discoverKilocodeModels (fetch path)", () => {
|
||||
|
||||
expect(requireModelById(models, "some/bad-window")).toMatchObject({
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
maxTokens: 65536,
|
||||
});
|
||||
expect(requireModelById(models, "some/bad-output")).toMatchObject({
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 128000,
|
||||
maxTokens: 65536,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("ensures kilo/auto is present even when API doesn't return it", async () => {
|
||||
it("ensures kilo-auto/balanced is present even when API doesn't return it", async () => {
|
||||
const mockFetch = vi.fn().mockResolvedValue(
|
||||
jsonResponse({
|
||||
data: [makeGatewayModel()],
|
||||
@@ -271,7 +278,7 @@ describe("discoverKilocodeModels (fetch path)", () => {
|
||||
);
|
||||
await withFetchPathTest(mockFetch, async () => {
|
||||
const models = await discoverKilocodeModels();
|
||||
expect(requireModelById(models, "kilo/auto").id).toBe("kilo/auto");
|
||||
expect(requireModelById(models, "kilo-auto/balanced").id).toBe("kilo-auto/balanced");
|
||||
expect(requireModelById(models, "anthropic/claude-sonnet-4").id).toBe(
|
||||
"anthropic/claude-sonnet-4",
|
||||
);
|
||||
@@ -299,7 +306,7 @@ describe("discoverKilocodeModels (fetch path)", () => {
|
||||
|
||||
it("keeps a later valid duplicate when an earlier entry is malformed", async () => {
|
||||
const malformedAutoModel = makeAutoModel({
|
||||
name: "Broken Kilo Auto",
|
||||
name: "Broken Auto Balanced",
|
||||
pricing: undefined,
|
||||
});
|
||||
|
||||
@@ -310,9 +317,9 @@ describe("discoverKilocodeModels (fetch path)", () => {
|
||||
);
|
||||
await withFetchPathTest(mockFetch, async () => {
|
||||
const models = await discoverKilocodeModels();
|
||||
const auto = requireModelById(models, "kilo/auto");
|
||||
expect(auto.name).toBe("Kilo: Auto");
|
||||
expect(auto.cost.input).toBeCloseTo(5);
|
||||
const auto = requireModelById(models, "kilo-auto/balanced");
|
||||
expect(auto.name).toBe("Auto Balanced");
|
||||
expect(auto.cost.input).toBeCloseTo(0.325);
|
||||
expect(requireModelById(models, "anthropic/claude-sonnet-4").id).toBe(
|
||||
"anthropic/claude-sonnet-4",
|
||||
);
|
||||
|
||||
@@ -14,9 +14,9 @@ import {
|
||||
const log = createSubsystemLogger("kilocode-models");
|
||||
|
||||
export const KILOCODE_BASE_URL = "https://api.kilo.ai/api/gateway/";
|
||||
export const KILOCODE_DEFAULT_MODEL_ID = "kilo/auto";
|
||||
export const KILOCODE_DEFAULT_MODEL_ID = "kilo-auto/balanced";
|
||||
export const KILOCODE_DEFAULT_MODEL_REF = `kilocode/${KILOCODE_DEFAULT_MODEL_ID}`;
|
||||
export const KILOCODE_DEFAULT_MODEL_NAME = "Kilo Auto";
|
||||
export const KILOCODE_DEFAULT_MODEL_NAME = "Auto Balanced";
|
||||
|
||||
type KilocodeModelCatalogEntry = {
|
||||
id: string;
|
||||
@@ -37,12 +37,12 @@ export const KILOCODE_MODEL_CATALOG: KilocodeModelCatalogEntry[] = [
|
||||
];
|
||||
|
||||
export const KILOCODE_DEFAULT_CONTEXT_WINDOW = 1000000;
|
||||
export const KILOCODE_DEFAULT_MAX_TOKENS = 128000;
|
||||
export const KILOCODE_DEFAULT_MAX_TOKENS = 65536;
|
||||
export const KILOCODE_DEFAULT_COST = {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
input: 0.325,
|
||||
output: 1.95,
|
||||
cacheRead: 0.0325,
|
||||
cacheWrite: 0.40625,
|
||||
};
|
||||
|
||||
export const KILOCODE_MODELS_URL = `${KILOCODE_BASE_URL}models`;
|
||||
|
||||
@@ -50,7 +50,7 @@ function isProxyReasoningUnsupported(modelId: string): boolean {
|
||||
}
|
||||
|
||||
function resolveKilocodeThinkingLevel(ctx: ProviderWrapStreamFnContext): ThinkLevel | undefined {
|
||||
if (ctx.modelId === "kilo/auto" || isProxyReasoningUnsupported(ctx.modelId)) {
|
||||
if (ctx.modelId === "kilo-auto/balanced" || isProxyReasoningUnsupported(ctx.modelId)) {
|
||||
return undefined;
|
||||
}
|
||||
return ctx.thinkingLevel;
|
||||
|
||||
@@ -64,6 +64,15 @@ describe("Kimi implicit provider (#22409)", () => {
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
},
|
||||
{
|
||||
id: "kimi-for-coding-highspeed",
|
||||
name: "Kimi K2.7 Code HighSpeed",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
},
|
||||
{
|
||||
id: "k3",
|
||||
name: "Kimi K3",
|
||||
@@ -100,24 +109,6 @@ describe("Kimi implicit provider (#22409)", () => {
|
||||
contextWindow: 1048576,
|
||||
maxTokens: 32768,
|
||||
},
|
||||
{
|
||||
id: "kimi-code",
|
||||
name: "Kimi Code (legacy kimi-code)",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
},
|
||||
{
|
||||
id: "k2p5",
|
||||
name: "Kimi Code (legacy k2p5)",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 262144,
|
||||
maxTokens: 32768,
|
||||
},
|
||||
],
|
||||
apiKey: "test-key",
|
||||
});
|
||||
|
||||
@@ -12,10 +12,9 @@ describe("kimi provider catalog", () => {
|
||||
expect(provider.headers).toEqual({ "User-Agent": "claude-code/0.1.0" });
|
||||
expect(provider.models.map((model) => model.id)).toEqual([
|
||||
"kimi-for-coding",
|
||||
"kimi-for-coding-highspeed",
|
||||
"k3",
|
||||
"k3[1m]",
|
||||
"kimi-code",
|
||||
"k2p5",
|
||||
]);
|
||||
expect(provider.models.find((model) => model.id === "k3")).toMatchObject({
|
||||
name: "Kimi K3",
|
||||
@@ -34,10 +33,17 @@ describe("kimi provider catalog", () => {
|
||||
});
|
||||
expect(provider.models.find((model) => model.id === "k3[1m]")).toMatchObject({
|
||||
name: "Kimi K3 (1M)",
|
||||
reasoning: true,
|
||||
contextWindow: 1_048_576,
|
||||
maxTokens: 32_768,
|
||||
});
|
||||
expect(provider.models.find((model) => model.id === "kimi-for-coding-highspeed")).toMatchObject(
|
||||
{
|
||||
name: "Kimi K2.7 Code HighSpeed",
|
||||
reasoning: true,
|
||||
contextWindow: 262_144,
|
||||
maxTokens: 32_768,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes legacy Kimi coding model ids to the stable API model id", () => {
|
||||
@@ -45,7 +51,9 @@ describe("kimi provider catalog", () => {
|
||||
expect(normalizeKimiCodingModelId("k2p5")).toBe("kimi-for-coding");
|
||||
expect(normalizeKimiCodingModelId("kimi-for-coding")).toBe("kimi-for-coding");
|
||||
expect(normalizeKimiCodingModelId("k3")).toBe("k3");
|
||||
expect(normalizeKimiCodingModelId("k3[1m]")).toBe("k3[1m]");
|
||||
expect(normalizeKimiCodingModelId("kimi-for-coding-highspeed")).toBe(
|
||||
"kimi-for-coding-highspeed",
|
||||
);
|
||||
expect(isKimiK3ModelId("k3")).toBe(true);
|
||||
expect(isKimiK3ModelId("k3[1m]")).toBe(true);
|
||||
expect(isKimiK3ModelId("kimi-for-coding")).toBe(false);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { KIMI_K3_MODEL_IDS } from "./provider-policy-api.js";
|
||||
const KIMI_BASE_URL = "https://api.kimi.com/coding/";
|
||||
const KIMI_CODING_USER_AGENT = "claude-code/0.1.0";
|
||||
const KIMI_DEFAULT_MODEL_ID = "kimi-for-coding";
|
||||
const KIMI_HIGHSPEED_MODEL_ID = "kimi-for-coding-highspeed";
|
||||
// Kimi's Claude Code endpoint uses k3[1m] as the wire id for the 1M plan;
|
||||
// normalizing it to k3 would lose the server-side context entitlement signal.
|
||||
const KIMI_LEGACY_MODEL_IDS = ["kimi-code", "k2p5"] as const;
|
||||
@@ -38,6 +39,15 @@ export function buildKimiCodingProvider(): ModelProviderConfig {
|
||||
contextWindow: KIMI_CODING_DEFAULT_CONTEXT_WINDOW,
|
||||
maxTokens: KIMI_CODING_DEFAULT_MAX_TOKENS,
|
||||
},
|
||||
{
|
||||
id: KIMI_HIGHSPEED_MODEL_ID,
|
||||
name: "Kimi K2.7 Code HighSpeed",
|
||||
reasoning: true,
|
||||
input: [...KIMI_CODING_INPUT],
|
||||
cost: KIMI_CODING_DEFAULT_COST,
|
||||
contextWindow: KIMI_CODING_DEFAULT_CONTEXT_WINDOW,
|
||||
maxTokens: KIMI_CODING_DEFAULT_MAX_TOKENS,
|
||||
},
|
||||
...KIMI_K3_MODEL_IDS.map((id) => ({
|
||||
id,
|
||||
name: id === "k3" ? "Kimi K3" : "Kimi K3 (1M)",
|
||||
@@ -56,15 +66,6 @@ export function buildKimiCodingProvider(): ModelProviderConfig {
|
||||
contextWindow: id === "k3" ? KIMI_CODING_DEFAULT_CONTEXT_WINDOW : 1_048_576,
|
||||
maxTokens: KIMI_CODING_DEFAULT_MAX_TOKENS,
|
||||
})),
|
||||
...KIMI_LEGACY_MODEL_IDS.map((id) => ({
|
||||
id,
|
||||
name: `Kimi Code (legacy ${id})`,
|
||||
reasoning: true,
|
||||
input: [...KIMI_CODING_INPUT],
|
||||
cost: KIMI_CODING_DEFAULT_COST,
|
||||
contextWindow: KIMI_CODING_DEFAULT_CONTEXT_WINDOW,
|
||||
maxTokens: KIMI_CODING_DEFAULT_MAX_TOKENS,
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ export type HermesCodexAuthCandidate = {
|
||||
const HERMES_REAUTH_PROVIDER_MAPPINGS = [
|
||||
{ sourceProvider: "anthropic", targetProvider: "anthropic" },
|
||||
{ sourceProvider: "nous", targetProvider: "nous" },
|
||||
{ sourceProvider: "qwen-oauth", targetProvider: "qwen-oauth" },
|
||||
{ sourceProvider: "qwen-oauth", targetProvider: "qwen" },
|
||||
{ sourceProvider: "qwen-cli", targetProvider: "qwen" },
|
||||
{ sourceProvider: "qwen-portal", targetProvider: "qwen" },
|
||||
{ sourceProvider: "minimax-oauth", targetProvider: "minimax-portal" },
|
||||
{ sourceProvider: "xai-oauth", targetProvider: "xai" },
|
||||
] as const;
|
||||
@@ -155,7 +157,7 @@ async function readHermesOAuthProviderIds(authPath: string | undefined): Promise
|
||||
export async function buildReauthenticationItems(source: HermesSource): Promise<MigrationItem[]> {
|
||||
const profileProviders = await readHermesOAuthProviderIds(source.authPath);
|
||||
const globalProviders = await readHermesOAuthProviderIds(source.globalAuthPath);
|
||||
return HERMES_REAUTH_PROVIDER_MAPPINGS.flatMap(({ sourceProvider, targetProvider }) => {
|
||||
const items = HERMES_REAUTH_PROVIDER_MAPPINGS.flatMap(({ sourceProvider, targetProvider }) => {
|
||||
const sourcePath = profileProviders.has(sourceProvider)
|
||||
? source.authPath
|
||||
: globalProviders.has(sourceProvider)
|
||||
@@ -169,8 +171,12 @@ export async function buildReauthenticationItems(source: HermesSource): Promise<
|
||||
id: `manual:auth-reauthenticate:${targetProvider}`,
|
||||
source: sourcePath,
|
||||
message: `Hermes ${sourceProvider} credentials cannot be reused safely by OpenClaw.`,
|
||||
recommendation: `Authenticate ${targetProvider} in OpenClaw after migration.`,
|
||||
recommendation:
|
||||
targetProvider === "qwen"
|
||||
? "Authenticate qwen with an API key after migration: openclaw onboard --auth-choice qwen-api-key."
|
||||
: `Authenticate ${targetProvider} in OpenClaw after migration.`,
|
||||
}),
|
||||
];
|
||||
});
|
||||
return [...new Map(items.map((item) => [item.id, item])).values()];
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ const HERMES_SPECIAL_BASE_URL_ENV_VARS: Record<string, readonly string[]> = {
|
||||
"openai-api": ["OPENAI_BASE_URL"],
|
||||
"xai-oauth": ["HERMES_XAI_BASE_URL", "XAI_BASE_URL"],
|
||||
"qwen-oauth": ["HERMES_QWEN_BASE_URL"],
|
||||
"qwen-cli": ["HERMES_QWEN_BASE_URL"],
|
||||
"qwen-portal": ["HERMES_QWEN_BASE_URL"],
|
||||
"minimax-cn": ["MINIMAX_CN_BASE_URL"],
|
||||
"alibaba-coding-plan": ["ALIBABA_CODING_PLAN_BASE_URL"],
|
||||
};
|
||||
|
||||
@@ -738,6 +738,14 @@ describe("Hermes migration config mapping", () => {
|
||||
expectedApi: "openai-completions",
|
||||
expectedBaseUrl: "https://dashscope-proxy.example.test/compatible-mode/v1",
|
||||
},
|
||||
{
|
||||
sourceProvider: "qwen-oauth",
|
||||
envName: "HERMES_QWEN_BASE_URL",
|
||||
envValue: "https://qwen-proxy.example.test/v1",
|
||||
targetProvider: "qwen",
|
||||
expectedApi: "openai-completions",
|
||||
expectedBaseUrl: "https://qwen-proxy.example.test/v1",
|
||||
},
|
||||
])(
|
||||
"imports $envName as the selected $sourceProvider endpoint",
|
||||
async ({ sourceProvider, envName, envValue, targetProvider, expectedApi, expectedBaseUrl }) => {
|
||||
|
||||
@@ -236,6 +236,8 @@ describe("Hermes migration file and skill items", () => {
|
||||
anthropic: {},
|
||||
nous: {},
|
||||
"qwen-oauth": {},
|
||||
"qwen-cli": {},
|
||||
"qwen-portal": {},
|
||||
[xaiProvider]: {},
|
||||
[minimaxProvider]: {},
|
||||
},
|
||||
@@ -257,7 +259,7 @@ describe("Hermes migration file and skill items", () => {
|
||||
expect(reauthItems.map((item) => item.reason)).toEqual([
|
||||
"Authenticate anthropic in OpenClaw after migration.",
|
||||
"Authenticate nous in OpenClaw after migration.",
|
||||
"Authenticate qwen-oauth in OpenClaw after migration.",
|
||||
"Authenticate qwen with an API key after migration: openclaw onboard --auth-choice qwen-api-key.",
|
||||
"Authenticate minimax-portal in OpenClaw after migration.",
|
||||
"Authenticate xai in OpenClaw after migration.",
|
||||
]);
|
||||
|
||||
@@ -69,7 +69,9 @@ describe("Hermes migration model planning", () => {
|
||||
["minimax-cn", "MiniMax-M2.7", "minimax/MiniMax-M2.7"],
|
||||
["opencode-zen", "gpt-5.4", "opencode/gpt-5.4"],
|
||||
["auto", "anthropic/claude-opus-4.6", "anthropic/claude-opus-4.6"],
|
||||
["qwen-cli", "qwen3.5-plus", "qwen-oauth/qwen3.5-plus"],
|
||||
["qwen-cli", "qwen3.5-plus", "qwen/qwen3.5-plus"],
|
||||
["qwen-oauth", "qwen3.5-plus", "qwen/qwen3.5-plus"],
|
||||
["qwen-portal", "qwen3.5-plus", "qwen/qwen3.5-plus"],
|
||||
["vertex", "gemini-3.1-pro", "google-vertex/gemini-3.1-pro"],
|
||||
["custom:My Local LLM", "local-model", "my-local-llm/local-model"],
|
||||
] as const;
|
||||
@@ -84,16 +86,34 @@ describe("Hermes migration model planning", () => {
|
||||
expect(plan.items.some((item) => item.id.startsWith("config:model-provider:"))).toBe(
|
||||
["alibaba", "dashscope", "minimax-cn"].includes(hermesProvider),
|
||||
);
|
||||
if (hermesProvider === "qwen-cli") {
|
||||
expect(
|
||||
plan.items.some(
|
||||
(item) => item.kind === "manual" && item.message?.includes("Qwen OAuth") === true,
|
||||
),
|
||||
).toBe(true);
|
||||
if (["qwen-cli", "qwen-oauth", "qwen-portal"].includes(hermesProvider)) {
|
||||
const reauthItem = plan.items.find((item) => item.id === "manual:auth-reauthenticate:qwen");
|
||||
expect(reauthItem?.reason).toBe(
|
||||
"Authenticate qwen with an API key after migration: openclaw onboard --auth-choice qwen-api-key.",
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("rewrites a provider-qualified retired Qwen model without a separate provider field", async () => {
|
||||
const root = await makeTempRoot();
|
||||
const source = path.join(root, "hermes");
|
||||
await writeFile(path.join(source, "config.yaml"), "model: qwen-oauth/qwen3.5-plus\n");
|
||||
|
||||
const plan = await buildHermesMigrationProvider().plan(
|
||||
makeContext({
|
||||
source,
|
||||
stateDir: path.join(root, "state"),
|
||||
workspaceDir: path.join(root, "workspace"),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(plan.items[0]?.details?.model).toBe("qwen/qwen3.5-plus");
|
||||
expect(plan.items.find((item) => item.id === "manual:auth-reauthenticate:qwen")?.reason).toBe(
|
||||
"Authenticate qwen with an API key after migration: openclaw onboard --auth-choice qwen-api-key.",
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["sk-kimi-placeholder", "kimi/kimi-k2.5"],
|
||||
["legacy-moonshot-placeholder", "moonshot/kimi-k2.5"],
|
||||
|
||||
@@ -59,9 +59,9 @@ const HERMES_PROVIDER_ALIASES: Record<string, string> = {
|
||||
"openai-codex": "openai",
|
||||
dashscope: "qwen",
|
||||
qwen: "qwen",
|
||||
"qwen-cli": "qwen-oauth",
|
||||
"qwen-oauth": "qwen-oauth",
|
||||
"qwen-portal": "qwen-oauth",
|
||||
"qwen-cli": "qwen",
|
||||
"qwen-oauth": "qwen",
|
||||
"qwen-portal": "qwen",
|
||||
"x-ai": "xai",
|
||||
"x-ai-oauth": "xai",
|
||||
"x.ai": "xai",
|
||||
@@ -110,7 +110,6 @@ const HERMES_CANONICAL_PROVIDER_IDS = new Set([
|
||||
"opencode-go",
|
||||
"opencode-zen",
|
||||
"openrouter",
|
||||
"qwen-oauth",
|
||||
"stepfun",
|
||||
"tencent-tokenhub",
|
||||
"xai",
|
||||
@@ -125,6 +124,7 @@ const HERMES_DYNAMIC_KIMI_PROVIDER_IDS = new Set([
|
||||
"kimi-for-coding",
|
||||
"moonshot",
|
||||
]);
|
||||
const HERMES_RETIRED_QWEN_PROVIDER_IDS = new Set(["qwen-cli", "qwen-oauth", "qwen-portal"]);
|
||||
|
||||
export function normalizeHermesProviderId(provider: string): string {
|
||||
const normalized = normalizeHermesCustomProviderId(provider);
|
||||
@@ -139,6 +139,25 @@ export function normalizeHermesCustomProviderId(provider: string): string {
|
||||
return withoutCustomPrefix.replaceAll(" ", "-");
|
||||
}
|
||||
|
||||
function isRetiredHermesQwenProviderValue(value: string): boolean {
|
||||
const slash = value.indexOf("/");
|
||||
const provider = slash > 0 ? value.slice(0, slash) : value;
|
||||
return HERMES_RETIRED_QWEN_PROVIDER_IDS.has(normalizeHermesCustomProviderId(provider));
|
||||
}
|
||||
|
||||
export function usesRetiredHermesQwenProvider(config: Record<string, unknown>): boolean {
|
||||
const model = asRecord(config.model);
|
||||
return [
|
||||
readString(config.provider),
|
||||
typeof config.model === "string" ? config.model : undefined,
|
||||
readString(model?.provider),
|
||||
readString(model?.default),
|
||||
readString(model?.model),
|
||||
readString(config.default_model),
|
||||
readString(config.model_name),
|
||||
].some((value) => value !== undefined && isRetiredHermesQwenProviderValue(value));
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
@@ -218,7 +237,10 @@ function resolveHermesKimiProviderId(
|
||||
|
||||
function hasExplicitHermesProvider(config: Record<string, unknown>, provider: string): boolean {
|
||||
const normalized = normalizeHermesCustomProviderId(provider);
|
||||
if (HERMES_CANONICAL_PROVIDER_IDS.has(normalized)) {
|
||||
if (
|
||||
HERMES_CANONICAL_PROVIDER_IDS.has(normalized) ||
|
||||
HERMES_RETIRED_QWEN_PROVIDER_IDS.has(normalized)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const providers = config.providers;
|
||||
@@ -261,6 +283,10 @@ function joinHermesProviderModel(
|
||||
env: Record<string, string>,
|
||||
): string {
|
||||
if (!provider) {
|
||||
const slash = model.indexOf("/");
|
||||
if (slash > 0 && isRetiredHermesQwenProviderValue(model)) {
|
||||
return `qwen/${model.slice(slash + 1)}`;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
if (provider.trim().toLowerCase() === "auto") {
|
||||
|
||||
@@ -21,7 +21,11 @@ import {
|
||||
HERMES_REASON_MODEL_PROVIDER_CONFLICT,
|
||||
} from "./items.js";
|
||||
import { buildHermesMemoryPlan, isMemoryOnlyMigration } from "./memory.js";
|
||||
import { resolveCurrentModelRef, resolveHermesModelRef } from "./model.js";
|
||||
import {
|
||||
resolveCurrentModelRef,
|
||||
resolveHermesModelRef,
|
||||
usesRetiredHermesQwenProvider,
|
||||
} from "./model.js";
|
||||
import { buildSecretItems } from "./secrets.js";
|
||||
import { buildSkillItems } from "./skills.js";
|
||||
import { discoverHermesSource, hasHermesSource } from "./source.js";
|
||||
@@ -93,16 +97,6 @@ export async function buildHermesPlan(ctx: MigrationProviderContext): Promise<Mi
|
||||
overwrite: ctx.overwrite,
|
||||
}),
|
||||
);
|
||||
if (modelRef.startsWith("qwen-oauth/")) {
|
||||
items.push(
|
||||
createMigrationManualItem({
|
||||
id: "manual:auth-reauthenticate:qwen-oauth",
|
||||
source: source.configPath ?? source.root,
|
||||
message: "Hermes Qwen OAuth uses the external Qwen CLI credential store.",
|
||||
recommendation: "Authenticate qwen-oauth in OpenClaw after migration.",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
const configItems = buildConfigItems({
|
||||
ctx,
|
||||
@@ -163,7 +157,22 @@ export async function buildHermesPlan(ctx: MigrationProviderContext): Promise<Mi
|
||||
);
|
||||
}
|
||||
items.push(...(await buildSkillItems({ source, targets, overwrite: ctx.overwrite })));
|
||||
items.push(...(await buildAuthItems({ ctx, source, targets })));
|
||||
const authItems = await buildAuthItems({ ctx, source, targets });
|
||||
if (
|
||||
usesRetiredHermesQwenProvider(config) &&
|
||||
!authItems.some((item) => item.id === "manual:auth-reauthenticate:qwen")
|
||||
) {
|
||||
authItems.unshift(
|
||||
createMigrationManualItem({
|
||||
id: "manual:auth-reauthenticate:qwen",
|
||||
source: source.configPath ?? source.root,
|
||||
message: "Hermes Qwen Portal OAuth and Qwen CLI credentials cannot be reused by OpenClaw.",
|
||||
recommendation:
|
||||
"Authenticate qwen with an API key after migration: openclaw onboard --auth-choice qwen-api-key.",
|
||||
}),
|
||||
);
|
||||
}
|
||||
items.push(...authItems);
|
||||
items.push(...(await buildSecretItems({ config, ctx, source, targets })));
|
||||
for (const archivePath of source.archivePaths) {
|
||||
items.push(
|
||||
|
||||
@@ -87,7 +87,6 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
"speech-02-turbo",
|
||||
"speech-01-hd",
|
||||
"speech-01-turbo",
|
||||
"speech-01-240228",
|
||||
]);
|
||||
expect(provider.voices).toContain("English_expressive_narrator");
|
||||
});
|
||||
@@ -186,7 +185,7 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://custom.api.com",
|
||||
model: "speech-01-240228",
|
||||
model: "speech-01-turbo",
|
||||
voiceId: "Chinese (Mandarin)_Warm_Girl",
|
||||
speed: 1.5,
|
||||
vol: 2,
|
||||
@@ -198,7 +197,7 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
timeoutMs: 30000,
|
||||
});
|
||||
expect(config.baseUrl).toBe("https://custom.api.com");
|
||||
expect(config.model).toBe("speech-01-240228");
|
||||
expect(config.model).toBe("speech-01-turbo");
|
||||
expect(config.voiceId).toBe("Chinese (Mandarin)_Warm_Girl");
|
||||
expect(config.speed).toBe(1.5);
|
||||
expect(config.vol).toBe(2);
|
||||
@@ -207,11 +206,11 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
|
||||
it("keeps trusted MINIMAX_API_HOST fallback for TTS baseUrl", () => {
|
||||
process.env.MINIMAX_API_HOST = "https://api.minimax.io/anthropic";
|
||||
process.env.MINIMAX_TTS_MODEL = "speech-01-240228";
|
||||
process.env.MINIMAX_TTS_MODEL = "speech-01-turbo";
|
||||
process.env.MINIMAX_TTS_VOICE_ID = "Chinese (Mandarin)_Gentle_Boy";
|
||||
const config = resolveProviderConfig({ rawConfig: {}, cfg: {} as never, timeoutMs: 30000 });
|
||||
expect(config.baseUrl).toBe("https://api.minimax.io");
|
||||
expect(config.model).toBe("speech-01-240228");
|
||||
expect(config.model).toBe("speech-01-turbo");
|
||||
expect(config.voiceId).toBe("Chinese (Mandarin)_Gentle_Boy");
|
||||
});
|
||||
|
||||
@@ -263,11 +262,11 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
it("handles model key", () => {
|
||||
const result = parseDirectiveToken({
|
||||
key: "model",
|
||||
value: "speech-01-240228",
|
||||
value: "speech-01-turbo",
|
||||
policy,
|
||||
});
|
||||
expect(result.handled).toBe(true);
|
||||
expect(result.overrides?.model).toBe("speech-01-240228");
|
||||
expect(result.overrides?.model).toBe("speech-01-turbo");
|
||||
});
|
||||
|
||||
it("handles speed key with valid value", () => {
|
||||
@@ -503,7 +502,7 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
cfg: {} as never,
|
||||
providerConfig: { apiKey: "sk-test" },
|
||||
providerOverrides: {
|
||||
model: "speech-01-240228",
|
||||
model: "speech-01-turbo",
|
||||
voiceId: "custom_voice",
|
||||
speed: 1.5,
|
||||
vol: 1.5,
|
||||
@@ -514,7 +513,7 @@ describe("buildMinimaxSpeechProvider", () => {
|
||||
});
|
||||
|
||||
const body = firstFetchBody();
|
||||
expect(body.model).toBe("speech-01-240228");
|
||||
expect(body.model).toBe("speech-01-turbo");
|
||||
const voiceSetting = body.voice_setting as Record<string, unknown>;
|
||||
expect(voiceSetting.voice_id).toBe("custom_voice");
|
||||
expect(voiceSetting.speed).toBe(1.5);
|
||||
|
||||
@@ -20,7 +20,6 @@ export const MINIMAX_TTS_MODELS = [
|
||||
"speech-02-turbo",
|
||||
"speech-01-hd",
|
||||
"speech-01-turbo",
|
||||
"speech-01-240228",
|
||||
] as const;
|
||||
|
||||
export const MINIMAX_TTS_VOICES = [
|
||||
|
||||
@@ -108,61 +108,64 @@ describe("moonshot provider plugin", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps Kimi K2.7 Code thinking always on without sending a thinking field", async () => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
const capturedStream = createCapturedThinkingConfigStream();
|
||||
it.each(["kimi-k2.7-code", "kimi-k2.7-code-highspeed"])(
|
||||
"keeps %s thinking always on without sending a thinking field",
|
||||
async (modelId) => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
const capturedStream = createCapturedThinkingConfigStream();
|
||||
|
||||
const wrapped = provider.wrapSimpleCompletionStreamFn?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.7-code",
|
||||
thinkingLevel: "off",
|
||||
streamFn: capturedStream.streamFn,
|
||||
} as never);
|
||||
|
||||
void wrapped?.(
|
||||
{
|
||||
api: "openai-completions",
|
||||
const wrapped = provider.wrapSimpleCompletionStreamFn?.({
|
||||
provider: "moonshot",
|
||||
id: "kimi-k2.7-code",
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(capturedStream.getCapturedPayload()).toEqual({
|
||||
config: { thinkingConfig: { thinkingBudget: -1 } },
|
||||
});
|
||||
expect(
|
||||
provider.wrapSimpleCompletionStreamFn?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.6",
|
||||
modelId,
|
||||
thinkingLevel: "off",
|
||||
streamFn: capturedStream.streamFn,
|
||||
} as never),
|
||||
).toBe(capturedStream.streamFn);
|
||||
expect(
|
||||
provider.resolveThinkingProfile?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.7-code",
|
||||
reasoning: true,
|
||||
} as never),
|
||||
).toEqual({
|
||||
levels: [{ id: "low", label: "on" }],
|
||||
defaultLevel: "low",
|
||||
preserveWhenCatalogReasoningFalse: true,
|
||||
});
|
||||
expect(
|
||||
provider.isModernModelRef?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.7-code",
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
provider.isModernModelRef?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.6",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
} as never);
|
||||
|
||||
void wrapped?.(
|
||||
{
|
||||
api: "openai-completions",
|
||||
provider: "moonshot",
|
||||
id: modelId,
|
||||
} as Model<"openai-completions">,
|
||||
{ messages: [] } as Context,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(capturedStream.getCapturedPayload()).toEqual({
|
||||
config: { thinkingConfig: { thinkingBudget: -1 } },
|
||||
});
|
||||
expect(
|
||||
provider.wrapSimpleCompletionStreamFn?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.6",
|
||||
streamFn: capturedStream.streamFn,
|
||||
} as never),
|
||||
).toBe(capturedStream.streamFn);
|
||||
expect(
|
||||
provider.resolveThinkingProfile?.({
|
||||
provider: "moonshot",
|
||||
modelId,
|
||||
reasoning: true,
|
||||
} as never),
|
||||
).toEqual({
|
||||
levels: [{ id: "low", label: "on" }],
|
||||
defaultLevel: "low",
|
||||
preserveWhenCatalogReasoningFalse: true,
|
||||
});
|
||||
expect(
|
||||
provider.isModernModelRef?.({
|
||||
provider: "moonshot",
|
||||
modelId,
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
provider.isModernModelRef?.({
|
||||
provider: "moonshot",
|
||||
modelId: "kimi-k2.6",
|
||||
}),
|
||||
).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it("exposes Kimi K3 as an always-max-thinking modern model", async () => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
|
||||
@@ -104,6 +104,20 @@
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2.7-code-highspeed",
|
||||
"name": "Kimi K2.7 Code HighSpeed",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 1.9,
|
||||
"output": 8,
|
||||
"cacheRead": 0.38,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2.5",
|
||||
"name": "Kimi K2.5",
|
||||
@@ -116,47 +130,6 @@
|
||||
"cacheRead": 0.1,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2-thinking",
|
||||
"name": "Kimi K2 Thinking",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2-thinking-turbo",
|
||||
"name": "Kimi K2 Thinking Turbo",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 262144,
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2-turbo",
|
||||
"name": "Kimi K2 Turbo",
|
||||
"input": ["text"],
|
||||
"contextWindow": 256000,
|
||||
"maxTokens": 16384,
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -43,10 +43,8 @@ describe("moonshot provider catalog", () => {
|
||||
"kimi-k2.6",
|
||||
"kimi-k3",
|
||||
"kimi-k2.7-code",
|
||||
"kimi-k2.7-code-highspeed",
|
||||
"kimi-k2.5",
|
||||
"kimi-k2-thinking",
|
||||
"kimi-k2-thinking-turbo",
|
||||
"kimi-k2-turbo",
|
||||
]);
|
||||
expect(requireMoonshotModel(provider, "kimi-k2.6").cost).toEqual({
|
||||
input: 0.95,
|
||||
@@ -91,6 +89,18 @@ describe("moonshot provider catalog", () => {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
});
|
||||
expect(requireMoonshotModel(provider, "kimi-k2.7-code-highspeed")).toMatchObject({
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
contextWindow: 262144,
|
||||
maxTokens: 262144,
|
||||
cost: {
|
||||
input: 1.9,
|
||||
output: 8,
|
||||
cacheRead: 0.38,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
});
|
||||
expect(requireMoonshotModel(provider, "kimi-k2.5").cost).toEqual({
|
||||
input: 0.6,
|
||||
output: 3,
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
import type { ProviderDefaultThinkingPolicyContext } from "openclaw/plugin-sdk/core";
|
||||
|
||||
export const KIMI_K2_7_CODE_MODEL_ID = "kimi-k2.7-code";
|
||||
export const KIMI_K2_7_CODE_HIGHSPEED_MODEL_ID = "kimi-k2.7-code-highspeed";
|
||||
export const KIMI_K3_MODEL_ID = "kimi-k3";
|
||||
|
||||
export function isMoonshotAlwaysThinkingModelId(modelId: string): boolean {
|
||||
const normalized = modelId.trim().toLowerCase();
|
||||
return normalized === KIMI_K2_7_CODE_MODEL_ID || normalized === KIMI_K3_MODEL_ID;
|
||||
return (
|
||||
normalized === KIMI_K2_7_CODE_MODEL_ID ||
|
||||
normalized === KIMI_K2_7_CODE_HIGHSPEED_MODEL_ID ||
|
||||
normalized === KIMI_K3_MODEL_ID
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveThinkingProfile(context: ProviderDefaultThinkingPolicyContext) {
|
||||
@@ -18,7 +23,7 @@ export function resolveThinkingProfile(context: ProviderDefaultThinkingPolicyCon
|
||||
preserveWhenCatalogReasoningFalse: true,
|
||||
};
|
||||
}
|
||||
if (modelId === KIMI_K2_7_CODE_MODEL_ID) {
|
||||
if (modelId === KIMI_K2_7_CODE_MODEL_ID || modelId === KIMI_K2_7_CODE_HIGHSPEED_MODEL_ID) {
|
||||
return {
|
||||
levels: [{ id: "low" as const, label: "on" }],
|
||||
defaultLevel: "low" as const,
|
||||
|
||||
@@ -40,10 +40,7 @@ import {
|
||||
|
||||
const DEFAULT_KIMI_BASE_URL = MOONSHOT_BASE_URL;
|
||||
const DEFAULT_KIMI_SEARCH_MODEL = MOONSHOT_DEFAULT_MODEL_ID;
|
||||
/** Models that require explicit thinking disablement for web search.
|
||||
* Reasoning variants (kimi-k2-thinking, kimi-k2-thinking-turbo) are excluded
|
||||
* because they default to thinking-enabled and disabling it would defeat their
|
||||
* purpose; they are also unlikely to be used for web search. */
|
||||
/** Models that require explicit thinking disablement for web search. */
|
||||
const KIMI_THINKING_MODELS = new Set(["kimi-k2.6", "kimi-k2.5"]);
|
||||
const KIMI_WEB_SEARCH_TOOL = {
|
||||
type: "builtin_function",
|
||||
|
||||
@@ -61,12 +61,12 @@ describe("nvidia onboard", () => {
|
||||
providerApi: "openai-completions",
|
||||
baseUrl: "https://integrate.api.nvidia.com/v1",
|
||||
legacyApi: "openai-completions",
|
||||
legacyModelId: "moonshotai/kimi-k2.5",
|
||||
legacyModelName: "Kimi K2.5",
|
||||
legacyModelId: "minimaxai/minimax-m2.7",
|
||||
legacyModelName: "MiniMax M2.7",
|
||||
});
|
||||
|
||||
expect(provider?.models.map((model) => model.id)).toEqual([
|
||||
"moonshotai/kimi-k2.5",
|
||||
"minimaxai/minimax-m2.7",
|
||||
"nvidia/nemotron-3-ultra-550b-a55b",
|
||||
"nvidia/nemotron-3-super-120b-a12b",
|
||||
"z-ai/glm-5.2",
|
||||
|
||||
@@ -68,6 +68,10 @@ describe("openrouter speech provider", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("advertises the documented ElevenLabs route", () => {
|
||||
expect(buildOpenRouterSpeechProvider().models).toContain("elevenlabs/eleven-turbo-v2");
|
||||
});
|
||||
|
||||
it("normalizes provider-owned speech config", () => {
|
||||
const provider = buildOpenRouterSpeechProvider();
|
||||
const resolved = provider.resolveConfig?.({
|
||||
|
||||
@@ -10,9 +10,9 @@ const DEFAULT_OPENROUTER_TTS_MODEL = "hexgrad/kokoro-82m";
|
||||
const DEFAULT_OPENROUTER_TTS_VOICE = "af_alloy";
|
||||
const OPENROUTER_TTS_MODELS = [
|
||||
DEFAULT_OPENROUTER_TTS_MODEL,
|
||||
"elevenlabs/eleven-turbo-v2",
|
||||
"google/gemini-3.1-flash-tts-preview",
|
||||
"mistralai/voxtral-mini-tts-2603",
|
||||
"elevenlabs/eleven-turbo-v2",
|
||||
] as const;
|
||||
const OPENROUTER_TTS_RESPONSE_FORMATS = ["mp3", "pcm"] as const;
|
||||
|
||||
|
||||
@@ -70,29 +70,19 @@ describe("qwen provider plugin", () => {
|
||||
expect(provider.suppressBuiltInModel).toBeUndefined();
|
||||
});
|
||||
|
||||
it("registers qwen-oauth as a portal provider", async () => {
|
||||
it("does not register retired Qwen Portal providers", async () => {
|
||||
const { providers } = await registerProviderPlugin({
|
||||
plugin: qwenPlugin,
|
||||
id: "qwen",
|
||||
name: "Qwen Provider",
|
||||
});
|
||||
const provider = requireRegisteredProvider(providers, "qwen-oauth");
|
||||
const retiredProviderIds = ["qwen-oauth", "qwen-portal", "qwen-cli"];
|
||||
|
||||
expect(provider.aliases).toEqual(["qwen-portal", "qwen-cli"]);
|
||||
expect(provider.envVars).toEqual(["QWEN_API_KEY"]);
|
||||
expect(provider.auth?.map((method) => method.id)).toEqual(["api-key"]);
|
||||
|
||||
const result = await provider.staticCatalog?.run({
|
||||
config: {},
|
||||
env: {},
|
||||
resolveProviderApiKey: () => ({}),
|
||||
} as never);
|
||||
const catalogProvider = requireCatalogProvider(result);
|
||||
expect(catalogProvider.baseUrl).toBe("https://portal.qwen.ai/v1");
|
||||
expect(catalogProvider.models?.map((model) => model.id)).toContain("qwen3.5-plus");
|
||||
expect(catalogProvider.models?.map((model) => model.id)).not.toContain(QWEN_36_FLASH_MODEL_ID);
|
||||
expect(catalogProvider.models?.map((model) => model.id)).not.toContain(QWEN_37_MAX_MODEL_ID);
|
||||
expect(catalogProvider.models?.map((model) => model.id)).not.toContain(QWEN_37_PLUS_MODEL_ID);
|
||||
expect(providers.map((provider) => provider.id)).not.toEqual(
|
||||
expect.arrayContaining(retiredProviderIds),
|
||||
);
|
||||
expect(manifest.providers).not.toEqual(expect.arrayContaining(retiredProviderIds));
|
||||
expect(manifest.modelCatalog.providers).not.toHaveProperty("qwen-oauth");
|
||||
});
|
||||
|
||||
it("registers canonical and legacy Token Plan owners without catalog aliasing", async () => {
|
||||
@@ -304,81 +294,4 @@ describe("qwen provider plugin", () => {
|
||||
const modelIds = tokenPlanProvider(globalAgain)?.models?.map((model) => model.id) ?? [];
|
||||
expect(new Set(modelIds).size).toBe(modelIds.length);
|
||||
});
|
||||
|
||||
it("reuses legacy qwen portal auth profiles for qwen-oauth catalog", async () => {
|
||||
const { providers } = await registerProviderPlugin({
|
||||
plugin: qwenPlugin,
|
||||
id: "qwen",
|
||||
name: "Qwen Provider",
|
||||
});
|
||||
const provider = requireRegisteredProvider(providers, "qwen-oauth");
|
||||
|
||||
const result = await provider.catalog?.run({
|
||||
config: {},
|
||||
env: {},
|
||||
resolveProviderApiKey: (providerId: string) =>
|
||||
providerId === "qwen-portal" ? { apiKey: "portal-token" } : {},
|
||||
} as never);
|
||||
|
||||
const catalogProvider = requireCatalogProvider(result);
|
||||
expect(catalogProvider.apiKey).toBe("portal-token");
|
||||
expect(catalogProvider.baseUrl).toBe("https://portal.qwen.ai/v1");
|
||||
});
|
||||
|
||||
it.each([["qwen-oauth"], ["qwen-portal"], ["qwen-cli"]])(
|
||||
"patches %s message payloads for portal compatibility",
|
||||
async (providerId) => {
|
||||
let patchedPayload: Record<string, unknown> | undefined;
|
||||
const streamFn = wrapQwenProviderStream({
|
||||
provider: providerId,
|
||||
thinkingLevel: "off",
|
||||
streamFn: ((
|
||||
_model: unknown,
|
||||
_context: unknown,
|
||||
options?: {
|
||||
onPayload?: (payload: Record<string, unknown>, model: unknown) => void;
|
||||
},
|
||||
) => {
|
||||
const payload = {
|
||||
messages: [
|
||||
{ role: "system", content: "system text" },
|
||||
{ role: "user", content: ["hello", { type: "text", text: "world" }] },
|
||||
],
|
||||
};
|
||||
options?.onPayload?.(payload, _model);
|
||||
patchedPayload = payload;
|
||||
return (async function* () {})();
|
||||
}) as never,
|
||||
} as never);
|
||||
|
||||
const stream = streamFn!(
|
||||
{
|
||||
provider: providerId,
|
||||
api: "openai-completions",
|
||||
id: "qwen3.5-plus",
|
||||
} as never,
|
||||
{} as never,
|
||||
{},
|
||||
) as AsyncIterable<unknown>;
|
||||
for await (const event of stream) {
|
||||
void event;
|
||||
// Drain stream so the payload hook runs.
|
||||
}
|
||||
|
||||
expect(patchedPayload?.vl_high_resolution_images).toBe(true);
|
||||
expect(patchedPayload?.messages).toEqual([
|
||||
{
|
||||
role: "system",
|
||||
content: [{ type: "text", text: "system text", cache_control: { type: "ephemeral" } }],
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "hello" },
|
||||
{ type: "text", text: "world" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -11,8 +11,6 @@ import {
|
||||
isQwenTokenPlanThinkingOnlyModelId,
|
||||
QWEN_BASE_URL,
|
||||
QWEN_DEFAULT_MODEL_REF,
|
||||
QWEN_OAUTH_DEFAULT_MODEL_REF,
|
||||
QWEN_OAUTH_PROVIDER_ID,
|
||||
QWEN_TOKEN_PLAN_DEFAULT_MODEL_REF,
|
||||
QWEN_TOKEN_PLAN_LEGACY_PROVIDER_ID,
|
||||
QWEN_TOKEN_PLAN_PROVIDER_ID,
|
||||
@@ -21,22 +19,16 @@ import {
|
||||
import {
|
||||
applyQwenConfig,
|
||||
applyQwenConfigCn,
|
||||
applyQwenOAuthConfig,
|
||||
applyQwenStandardConfig,
|
||||
applyQwenStandardConfigCn,
|
||||
applyQwenTokenPlanConfig,
|
||||
} from "./onboard.js";
|
||||
import {
|
||||
buildQwenOAuthProvider,
|
||||
buildQwenProvider,
|
||||
buildQwenTokenPlanProvider,
|
||||
} from "./provider-catalog.js";
|
||||
import { buildQwenProvider, buildQwenTokenPlanProvider } from "./provider-catalog.js";
|
||||
import { wrapQwenProviderStream } from "./stream.js";
|
||||
import { buildQwenVideoGenerationProvider } from "./video-generation-provider.js";
|
||||
|
||||
const PROVIDER_ID = "qwen";
|
||||
const LEGACY_PROVIDER_ID = "modelstudio";
|
||||
const QWEN_OAUTH_AUTH_PROVIDER_IDS = [QWEN_OAUTH_PROVIDER_ID, "qwen-portal", "qwen-cli"] as const;
|
||||
const QWEN_TOKEN_PLAN_THINKING_LEVEL_IDS = [
|
||||
"off",
|
||||
"minimal",
|
||||
@@ -117,7 +109,7 @@ function createQwenTokenPlanAuthMethod(region: "global" | "cn") {
|
||||
choiceHint: `Endpoint: ${host}`,
|
||||
groupId: "qwen",
|
||||
groupLabel: "Qwen Cloud",
|
||||
groupHint: "Standard / Coding Plan / Token Plan / OAuth",
|
||||
groupHint: "Standard / Coding Plan / Token Plan",
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -279,62 +271,6 @@ export default defineSingleProviderPluginEntry({
|
||||
},
|
||||
},
|
||||
register(api) {
|
||||
api.registerProvider({
|
||||
id: QWEN_OAUTH_PROVIDER_ID,
|
||||
label: "Qwen OAuth",
|
||||
docsPath: "/providers/qwen",
|
||||
aliases: ["qwen-portal", "qwen-cli"],
|
||||
envVars: ["QWEN_API_KEY"],
|
||||
auth: [
|
||||
createProviderApiKeyAuthMethod({
|
||||
providerId: QWEN_OAUTH_PROVIDER_ID,
|
||||
methodId: "api-key",
|
||||
label: "Qwen OAuth token",
|
||||
hint: "Portal token for portal.qwen.ai",
|
||||
optionKey: "qwenOauthToken",
|
||||
flagName: "--qwen-oauth-token",
|
||||
envVar: "QWEN_API_KEY",
|
||||
promptMessage: "Enter Qwen OAuth token",
|
||||
defaultModel: QWEN_OAUTH_DEFAULT_MODEL_REF,
|
||||
applyConfig: (cfg) => applyQwenOAuthConfig(cfg),
|
||||
wizard: {
|
||||
choiceId: QWEN_OAUTH_PROVIDER_ID,
|
||||
choiceLabel: "Qwen OAuth",
|
||||
choiceHint: "Portal token for portal.qwen.ai",
|
||||
groupId: "qwen",
|
||||
groupLabel: "Qwen Cloud",
|
||||
groupHint: "Standard / Coding Plan / OAuth",
|
||||
},
|
||||
}),
|
||||
],
|
||||
catalog: {
|
||||
order: "simple",
|
||||
run: async (ctx) => {
|
||||
const apiKey = QWEN_OAUTH_AUTH_PROVIDER_IDS.map(
|
||||
(providerId) => ctx.resolveProviderApiKey(providerId).apiKey,
|
||||
).find(
|
||||
(candidate): candidate is string =>
|
||||
typeof candidate === "string" && candidate.length > 0,
|
||||
);
|
||||
if (!apiKey) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
provider: {
|
||||
...buildQwenOAuthProvider(),
|
||||
apiKey,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
staticCatalog: {
|
||||
order: "simple",
|
||||
run: async () => ({
|
||||
provider: buildQwenOAuthProvider(),
|
||||
}),
|
||||
},
|
||||
wrapStreamFn: wrapQwenProviderStream,
|
||||
});
|
||||
api.registerProvider({
|
||||
id: QWEN_TOKEN_PLAN_PROVIDER_ID,
|
||||
label: "Qwen Token Plan",
|
||||
|
||||
@@ -14,6 +14,15 @@ if (!describeQwenVideo) {
|
||||
throw new Error("expected Qwen video description capability");
|
||||
}
|
||||
|
||||
describe("qwen media understanding provider", () => {
|
||||
it("uses a currently served multimodal default", () => {
|
||||
expect(qwenProvider.defaultModels).toEqual({
|
||||
image: "qwen3.6-plus",
|
||||
video: "qwen3.6-plus",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function oversizedJsonResponse(params: { chunkCount: number; chunkSize: number }): {
|
||||
response: Response;
|
||||
getReadCount: () => number;
|
||||
|
||||
@@ -18,12 +18,12 @@ import {
|
||||
} from "openclaw/plugin-sdk/provider-http";
|
||||
import { QWEN_STANDARD_GLOBAL_BASE_URL } from "./models.js";
|
||||
|
||||
const DEFAULT_QWEN_VIDEO_MODEL = "qwen-vl-max-latest";
|
||||
const DEFAULT_QWEN_MEDIA_MODEL = "qwen3.6-plus";
|
||||
const DEFAULT_QWEN_VIDEO_PROMPT = "Describe the video in detail.";
|
||||
|
||||
async function describeQwenVideo(params: VideoDescriptionRequest): Promise<VideoDescriptionResult> {
|
||||
const fetchFn = params.fetchFn ?? fetch;
|
||||
const model = resolveMediaUnderstandingString(params.model, DEFAULT_QWEN_VIDEO_MODEL);
|
||||
const model = resolveMediaUnderstandingString(params.model, DEFAULT_QWEN_MEDIA_MODEL);
|
||||
const mime = resolveMediaUnderstandingString(params.mime, "video/mp4");
|
||||
const prompt = resolveMediaUnderstandingString(params.prompt, DEFAULT_QWEN_VIDEO_PROMPT);
|
||||
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
|
||||
@@ -82,8 +82,8 @@ export function buildQwenMediaUnderstandingProvider(): MediaUnderstandingProvide
|
||||
id: "qwen",
|
||||
capabilities: ["image", "video"],
|
||||
defaultModels: {
|
||||
image: "qwen-vl-max-latest",
|
||||
video: DEFAULT_QWEN_VIDEO_MODEL,
|
||||
image: DEFAULT_QWEN_MEDIA_MODEL,
|
||||
video: DEFAULT_QWEN_MEDIA_MODEL,
|
||||
},
|
||||
autoPriority: {
|
||||
video: 15,
|
||||
|
||||
@@ -14,8 +14,6 @@ export const QWEN_CN_BASE_URL = "https://coding.dashscope.aliyuncs.com/v1";
|
||||
export const QWEN_STANDARD_CN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
||||
export const QWEN_STANDARD_GLOBAL_BASE_URL =
|
||||
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||
export const QWEN_OAUTH_PROVIDER_ID = "qwen-oauth";
|
||||
export const QWEN_OAUTH_BASE_URL = "https://portal.qwen.ai/v1";
|
||||
export const QWEN_TOKEN_PLAN_PROVIDER_ID = "qwen-token-plan";
|
||||
export const QWEN_TOKEN_PLAN_LEGACY_PROVIDER_ID = "bailian-token-plan";
|
||||
export const QWEN_TOKEN_PLAN_GLOBAL_BASE_URL =
|
||||
@@ -35,7 +33,6 @@ export const QWEN_DEFAULT_COST = {
|
||||
cacheWrite: 0,
|
||||
};
|
||||
export const QWEN_DEFAULT_MODEL_REF = `qwen/${QWEN_DEFAULT_MODEL_ID}`;
|
||||
export const QWEN_OAUTH_DEFAULT_MODEL_REF = `qwen-oauth/${QWEN_DEFAULT_MODEL_ID}`;
|
||||
export const QWEN_TOKEN_PLAN_DEFAULT_MODEL_ID = QWEN_37_PLUS_MODEL_ID;
|
||||
export const QWEN_TOKEN_PLAN_DEFAULT_MODEL_REF = `${QWEN_TOKEN_PLAN_PROVIDER_ID}/${QWEN_TOKEN_PLAN_DEFAULT_MODEL_ID}`;
|
||||
|
||||
@@ -347,12 +344,6 @@ const QWEN_STANDARD_ONLY_MODEL_IDS = new Set<string>([
|
||||
QWEN_37_MAX_MODEL_ID,
|
||||
]);
|
||||
|
||||
const QWEN_OAUTH_UNSUPPORTED_MODEL_IDS = new Set<string>([
|
||||
QWEN_36_FLASH_MODEL_ID,
|
||||
QWEN_37_MAX_MODEL_ID,
|
||||
QWEN_37_PLUS_MODEL_ID,
|
||||
]);
|
||||
|
||||
export function isQwenStandardOnlyModelId(modelId: string): boolean {
|
||||
return QWEN_STANDARD_ONLY_MODEL_IDS.has(modelId);
|
||||
}
|
||||
@@ -407,12 +398,6 @@ export function buildQwenDefaultModelDefinition(): ModelDefinitionConfig {
|
||||
return buildQwenModelDefinition({ id: QWEN_DEFAULT_MODEL_ID });
|
||||
}
|
||||
|
||||
export function buildQwenOAuthModelCatalog(): ReadonlyArray<ModelDefinitionConfig> {
|
||||
return QWEN_MODEL_CATALOG.filter((model) => !QWEN_OAUTH_UNSUPPORTED_MODEL_IDS.has(model.id)).map(
|
||||
(model) => Object.assign({}, model, { maxTokens: 65_536 }),
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated Use QWEN_BASE_URL. */
|
||||
export const MODELSTUDIO_BASE_URL = QWEN_BASE_URL;
|
||||
/** @deprecated Use QWEN_GLOBAL_BASE_URL. */
|
||||
|
||||
@@ -7,8 +7,6 @@ import {
|
||||
QWEN_CN_BASE_URL,
|
||||
QWEN_DEFAULT_MODEL_REF,
|
||||
QWEN_GLOBAL_BASE_URL,
|
||||
QWEN_OAUTH_DEFAULT_MODEL_REF,
|
||||
QWEN_OAUTH_PROVIDER_ID,
|
||||
QWEN_STANDARD_CN_BASE_URL,
|
||||
QWEN_STANDARD_GLOBAL_BASE_URL,
|
||||
QWEN_TOKEN_PLAN_DEFAULT_MODEL_REF,
|
||||
@@ -16,11 +14,7 @@ import {
|
||||
type QwenTokenPlanRegion,
|
||||
resolveQwenTokenPlanBaseUrl,
|
||||
} from "./models.js";
|
||||
import {
|
||||
buildQwenOAuthProvider,
|
||||
buildQwenProvider,
|
||||
buildQwenTokenPlanProvider,
|
||||
} from "./provider-catalog.js";
|
||||
import { buildQwenProvider, buildQwenTokenPlanProvider } from "./provider-catalog.js";
|
||||
|
||||
const qwenPresetAppliers = createModelCatalogPresetAppliers<[string]>({
|
||||
primaryModelRef: QWEN_DEFAULT_MODEL_REF,
|
||||
@@ -42,23 +36,6 @@ const qwenPresetAppliers = createModelCatalogPresetAppliers<[string]>({
|
||||
},
|
||||
});
|
||||
|
||||
const qwenOAuthPresetAppliers = createModelCatalogPresetAppliers<[]>({
|
||||
primaryModelRef: QWEN_OAUTH_DEFAULT_MODEL_REF,
|
||||
resolveParams: () => {
|
||||
const provider = buildQwenOAuthProvider();
|
||||
return {
|
||||
providerId: QWEN_OAUTH_PROVIDER_ID,
|
||||
api: provider.api ?? "openai-completions",
|
||||
baseUrl: provider.baseUrl,
|
||||
catalogModels: provider.models ?? [],
|
||||
aliases: [
|
||||
...(provider.models ?? []).map((model) => `qwen-oauth/${model.id}`),
|
||||
{ modelRef: QWEN_OAUTH_DEFAULT_MODEL_REF, alias: "Qwen OAuth" },
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const qwenTokenPlanPresetAppliers = createModelCatalogPresetAppliers<[string]>({
|
||||
primaryModelRef: QWEN_TOKEN_PLAN_DEFAULT_MODEL_REF,
|
||||
resolveParams: (_cfg: OpenClawConfig, baseUrl: string) => {
|
||||
@@ -92,10 +69,6 @@ export function applyQwenStandardConfigCn(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return qwenPresetAppliers.applyConfig(cfg, QWEN_STANDARD_CN_BASE_URL);
|
||||
}
|
||||
|
||||
export function applyQwenOAuthConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return qwenOAuthPresetAppliers.applyConfig(cfg);
|
||||
}
|
||||
|
||||
export function applyQwenTokenPlanConfig(
|
||||
cfg: OpenClawConfig,
|
||||
region: QwenTokenPlanRegion,
|
||||
|
||||
@@ -10,16 +10,9 @@
|
||||
"qwencloud",
|
||||
"modelstudio",
|
||||
"dashscope",
|
||||
"qwen-oauth",
|
||||
"qwen-portal",
|
||||
"qwen-cli",
|
||||
"qwen-token-plan",
|
||||
"bailian-token-plan"
|
||||
],
|
||||
"providerAuthAliases": {
|
||||
"qwen-portal": "qwen-oauth",
|
||||
"qwen-cli": "qwen-oauth"
|
||||
},
|
||||
"providerEndpoints": [
|
||||
{
|
||||
"endpointClass": "modelstudio-native",
|
||||
@@ -31,10 +24,6 @@
|
||||
"https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
|
||||
"https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"endpointClass": "qwen-portal-native",
|
||||
"baseUrls": ["https://portal.qwen.ai/v1"]
|
||||
}
|
||||
],
|
||||
"providerRequest": {
|
||||
@@ -51,15 +40,6 @@
|
||||
"dashscope": {
|
||||
"family": "modelstudio"
|
||||
},
|
||||
"qwen-oauth": {
|
||||
"family": "qwen-portal"
|
||||
},
|
||||
"qwen-portal": {
|
||||
"family": "qwen-portal"
|
||||
},
|
||||
"qwen-cli": {
|
||||
"family": "qwen-portal"
|
||||
},
|
||||
"qwen-token-plan": {
|
||||
"family": "modelstudio"
|
||||
},
|
||||
@@ -69,14 +49,6 @@
|
||||
}
|
||||
},
|
||||
"modelCatalog": {
|
||||
"aliases": {
|
||||
"qwen-portal": {
|
||||
"provider": "qwen-oauth"
|
||||
},
|
||||
"qwen-cli": {
|
||||
"provider": "qwen-oauth"
|
||||
}
|
||||
},
|
||||
"suppressions": [
|
||||
{
|
||||
"provider": "qwen",
|
||||
@@ -116,138 +88,6 @@
|
||||
}
|
||||
],
|
||||
"providers": {
|
||||
"qwen-oauth": {
|
||||
"baseUrl": "https://portal.qwen.ai/v1",
|
||||
"api": "openai-completions",
|
||||
"models": [
|
||||
{
|
||||
"id": "qwen3.5-plus",
|
||||
"name": "qwen3.5-plus",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "qwen3.6-plus",
|
||||
"name": "qwen3.6-plus",
|
||||
"reasoning": true,
|
||||
"input": ["text", "image"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "qwen3-max-2026-01-23",
|
||||
"name": "qwen3-max-2026-01-23",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "qwen3-coder-next",
|
||||
"name": "qwen3-coder-next",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "qwen3-coder-plus",
|
||||
"name": "qwen3-coder-plus",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "MiniMax-M2.5",
|
||||
"name": "MiniMax-M2.5",
|
||||
"reasoning": true,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "glm-5",
|
||||
"name": "glm-5",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "glm-4.7",
|
||||
"name": "glm-4.7",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 202752,
|
||||
"maxTokens": 65536
|
||||
},
|
||||
{
|
||||
"id": "kimi-k2.5",
|
||||
"name": "kimi-k2.5",
|
||||
"reasoning": false,
|
||||
"input": ["text", "image"],
|
||||
"cost": {
|
||||
"input": 0,
|
||||
"output": 0,
|
||||
"cacheRead": 0,
|
||||
"cacheWrite": 0
|
||||
},
|
||||
"contextWindow": 262144,
|
||||
"maxTokens": 65536
|
||||
}
|
||||
]
|
||||
},
|
||||
"qwen-token-plan": {
|
||||
"baseUrl": "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1",
|
||||
"api": "openai-completions",
|
||||
@@ -393,8 +233,8 @@
|
||||
"qwen": {
|
||||
"capabilities": ["image", "video"],
|
||||
"defaultModels": {
|
||||
"image": "qwen-vl-max-latest",
|
||||
"video": "qwen-vl-max-latest"
|
||||
"image": "qwen3.6-plus",
|
||||
"video": "qwen3.6-plus"
|
||||
},
|
||||
"autoPriority": {
|
||||
"video": 15
|
||||
@@ -407,10 +247,6 @@
|
||||
"id": "qwen",
|
||||
"envVars": ["QWEN_API_KEY", "MODELSTUDIO_API_KEY", "DASHSCOPE_API_KEY"]
|
||||
},
|
||||
{
|
||||
"id": "qwen-oauth",
|
||||
"envVars": ["QWEN_API_KEY"]
|
||||
},
|
||||
{
|
||||
"id": "qwen-token-plan",
|
||||
"envVars": ["QWEN_TOKEN_PLAN_API_KEY"]
|
||||
@@ -482,21 +318,6 @@
|
||||
"cliOption": "--modelstudio-api-key <key>",
|
||||
"cliDescription": "Qwen Cloud Coding Plan API key (Global/Intl)"
|
||||
},
|
||||
{
|
||||
"provider": "qwen-oauth",
|
||||
"method": "api-key",
|
||||
"choiceId": "qwen-oauth",
|
||||
"appGuidedSecret": true,
|
||||
"choiceLabel": "Qwen OAuth",
|
||||
"choiceHint": "Portal token for portal.qwen.ai",
|
||||
"groupId": "qwen",
|
||||
"groupLabel": "Qwen Cloud",
|
||||
"groupHint": "Standard / Coding Plan / OAuth",
|
||||
"optionKey": "qwenOauthToken",
|
||||
"cliFlag": "--qwen-oauth-token",
|
||||
"cliOption": "--qwen-oauth-token <token>",
|
||||
"cliDescription": "Qwen OAuth token"
|
||||
},
|
||||
{
|
||||
"provider": "qwen-token-plan",
|
||||
"method": "api-key",
|
||||
@@ -506,7 +327,7 @@
|
||||
"choiceHint": "Endpoint: token-plan.ap-southeast-1.maas.aliyuncs.com",
|
||||
"groupId": "qwen",
|
||||
"groupLabel": "Qwen Cloud",
|
||||
"groupHint": "Standard / Coding Plan / Token Plan / OAuth",
|
||||
"groupHint": "Standard / Coding Plan / Token Plan",
|
||||
"optionKey": "qwenTokenPlanApiKey",
|
||||
"cliFlag": "--qwen-token-plan-api-key",
|
||||
"cliOption": "--qwen-token-plan-api-key <key>",
|
||||
@@ -521,7 +342,7 @@
|
||||
"choiceHint": "Endpoint: token-plan.cn-beijing.maas.aliyuncs.com",
|
||||
"groupId": "qwen",
|
||||
"groupLabel": "Qwen Cloud",
|
||||
"groupHint": "Standard / Coding Plan / Token Plan / OAuth",
|
||||
"groupHint": "Standard / Coding Plan / Token Plan",
|
||||
"optionKey": "qwenTokenPlanApiKeyCn",
|
||||
"cliFlag": "--qwen-token-plan-api-key-cn",
|
||||
"cliOption": "--qwen-token-plan-api-key-cn <key>",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user