diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7639338d7..fe8a0f11b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,16 +60,31 @@ jobs: bun test src/features/opencode-skill-loader/loader.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts + # src/shared mock-heavy files (mock.module pollutes connected-providers-cache and legacy-plugin-warning) + bun test src/shared/model-capabilities.test.ts + bun test src/shared/log-legacy-plugin-startup-warning.test.ts + bun test src/shared/model-error-classifier.test.ts + bun test src/shared/opencode-message-dir.test.ts + # session-recovery mock isolation (recover-tool-result-missing mocks ./storage) + bun test src/hooks/session-recovery/recover-tool-result-missing.test.ts - name: Run remaining tests run: | # Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files # that were already run in isolation above. + # Excluded from src/shared: model-capabilities, log-legacy-plugin-startup-warning, model-error-classifier, opencode-message-dir # Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts # Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all) # Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts + # Build src/shared file list excluding mock-heavy files already run in isolation + SHARED_FILES=$(find src/shared -name '*.test.ts' \ + ! -name 'model-capabilities.test.ts' \ + ! -name 'log-legacy-plugin-startup-warning.test.ts' \ + ! -name 'model-error-classifier.test.ts' \ + ! -name 'opencode-message-dir.test.ts' \ + | sort | tr '\n' ' ') bun test bin script src/config src/mcp src/index.test.ts \ - src/agents src/shared \ + src/agents $SHARED_FILES \ src/cli/run src/cli/config-manager src/cli/mcp-oauth \ src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \ src/cli/config-manager.test.ts \ @@ -82,6 +97,7 @@ jobs: src/tools/call-omo-agent/background-executor.test.ts \ src/tools/call-omo-agent/subagent-session-creator.test.ts \ src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \ + src/hooks/session-recovery/detect-error-type.test.ts src/hooks/session-recovery/index.test.ts src/hooks/session-recovery/recover-empty-content-message-sdk.test.ts src/hooks/session-recovery/resume.test.ts src/hooks/session-recovery/storage \ src/hooks/claude-code-compatibility \ src/hooks/context-injection \ src/hooks/provider-toast \ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8a6f6e50d..1c90014f7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -61,16 +61,31 @@ jobs: bun test src/features/opencode-skill-loader/loader.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts + # src/shared mock-heavy files (mock.module pollutes connected-providers-cache and legacy-plugin-warning) + bun test src/shared/model-capabilities.test.ts + bun test src/shared/log-legacy-plugin-startup-warning.test.ts + bun test src/shared/model-error-classifier.test.ts + bun test src/shared/opencode-message-dir.test.ts + # session-recovery mock isolation (recover-tool-result-missing mocks ./storage) + bun test src/hooks/session-recovery/recover-tool-result-missing.test.ts - name: Run remaining tests run: | # Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files # that were already run in isolation above. + # Excluded from src/shared: model-capabilities, log-legacy-plugin-startup-warning, model-error-classifier, opencode-message-dir # Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts # Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all) # Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts + # Build src/shared file list excluding mock-heavy files already run in isolation + SHARED_FILES=$(find src/shared -name '*.test.ts' \ + ! -name 'model-capabilities.test.ts' \ + ! -name 'log-legacy-plugin-startup-warning.test.ts' \ + ! -name 'model-error-classifier.test.ts' \ + ! -name 'opencode-message-dir.test.ts' \ + | sort | tr '\n' ' ') bun test bin script src/config src/mcp src/index.test.ts \ - src/agents src/shared \ + src/agents $SHARED_FILES \ src/cli/run src/cli/config-manager src/cli/mcp-oauth \ src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \ src/cli/config-manager.test.ts \ @@ -83,6 +98,7 @@ jobs: src/tools/call-omo-agent/background-executor.test.ts \ src/tools/call-omo-agent/subagent-session-creator.test.ts \ src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \ + src/hooks/session-recovery/detect-error-type.test.ts src/hooks/session-recovery/index.test.ts src/hooks/session-recovery/recover-empty-content-message-sdk.test.ts src/hooks/session-recovery/resume.test.ts src/hooks/session-recovery/storage \ src/hooks/claude-code-compatibility \ src/hooks/context-injection \ src/hooks/provider-toast \ diff --git a/.github/workflows/refresh-model-capabilities.yml b/.github/workflows/refresh-model-capabilities.yml new file mode 100644 index 000000000..dd34e43ed --- /dev/null +++ b/.github/workflows/refresh-model-capabilities.yml @@ -0,0 +1,46 @@ +name: Refresh Model Capabilities + +on: + schedule: + - cron: "17 4 * * 1" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + refresh: + runs-on: ubuntu-latest + if: github.repository == 'code-yeongyu/oh-my-openagent' + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + env: + BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi" + + - name: Refresh bundled model capabilities snapshot + run: bun run build:model-capabilities + + - name: Validate capability guardrails + run: bun run test:model-capabilities + + - name: Create refresh pull request + uses: peter-evans/create-pull-request@v7 + with: + commit-message: "chore: refresh model capabilities snapshot" + title: "chore: refresh model capabilities snapshot" + body: | + Automated refresh of `src/generated/model-capabilities.generated.json` from `https://models.dev/api.json`. + + This keeps the bundled capability snapshot aligned with upstream model metadata without relying on manual refreshes. + branch: automation/refresh-model-capabilities + delete-branch: true + labels: | + maintenance diff --git a/README.ja.md b/README.ja.md index c456f9234..b9cea1105 100644 --- a/README.ja.md +++ b/README.ja.md @@ -168,7 +168,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 -**Hephaestus** (`gpt-5.3-codex`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* +**Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 @@ -176,7 +176,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu > Anthropicが[私たちのせいでOpenCodeをブロックしました。](https://x.com/thdxr/status/2010149530486911014) だからこそHephaestusは「正当なる職人 (The Legitimate Craftsman)」と呼ばれているのです。皮肉を込めています。 > -> Opusで最もよく動きますが、Kimi K2.5 + GPT-5.3 Codexの組み合わせだけでも、バニラのClaude Codeを軽く凌駕します。設定は一切不要です。 +> Opusで最もよく動きますが、Kimi K2.5 + GPT-5.4の組み合わせだけでも、バニラのClaude Codeを軽く凌駕します。設定は一切不要です。 ### エージェントの��ーケストレーション diff --git a/README.ko.md b/README.ko.md index 560ea7e6b..19524e98c 100644 --- a/README.ko.md +++ b/README.ko.md @@ -162,7 +162,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. -**Hephaestus** (`gpt-5.3-codex`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* +**Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. @@ -170,7 +170,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu > Anthropic이 [우리 때문에 OpenCode를 막아버렸습니다.](https://x.com/thdxr/status/2010149530486911014) 그래서 Hephaestus의 별명이 "진정한 장인(The Legitimate Craftsman)"인 겁니다. (어디서 많이 들어본 이름이죠?) 아이러니를 노렸습니다. > -> Opus에서 제일 잘 돌아가긴 하지만, Kimi K2.5 + GPT-5.3 Codex 조합만으로도 바닐라 Claude Code는 가볍게 바릅니다. 설정도 필요 없습니다. +> Opus에서 제일 잘 돌아가긴 하지만, Kimi K2.5 + GPT-5.4 조합만으로도 바닐라 Claude Code는 가볍게 바릅니다. 설정도 필요 없습니다. ### 에이전트 오케스트레이션 diff --git a/README.md b/README.md index b6c500d5d..b3dcb82df 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,8 @@ Fetch the installation guide and follow it: curl -s https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md ``` +**Note**: Use the published package and binary name `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files still commonly use `oh-my-opencode.json` or `oh-my-opencode.jsonc`, and both legacy and renamed basenames are recognized during the transition. + --- ## Skip This README @@ -164,7 +166,7 @@ Even only with following subscriptions, ultrawork will work well (this project i **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. -**Hephaestus** (`gpt-5.3-codex`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* +**Hephaestus** (`gpt-5.4`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched. @@ -172,7 +174,7 @@ Every agent is tuned to its model's specific strengths. No manual model-juggling > Anthropic [blocked OpenCode because of us.](https://x.com/thdxr/status/2010149530486911014) That's why Hephaestus is called "The Legitimate Craftsman." The irony is intentional. > -> We run best on Opus, but Kimi K2.5 + GPT-5.3 Codex already beats vanilla Claude Code. Zero config needed. +> We run best on Opus, but Kimi K2.5 + GPT-5.4 already beats vanilla Claude Code. Zero config needed. ### Agent Orchestration @@ -273,11 +275,11 @@ To remove oh-my-opencode: 1. **Remove the plugin from your OpenCode config** - Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove `"oh-my-opencode"` from the `plugin` array: + Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove either `"oh-my-openagent"` or the legacy `"oh-my-opencode"` entry from the `plugin` array: ```bash # Using jq - jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \ + jq '.plugin = [.plugin[] | select(. != "oh-my-openagent" and . != "oh-my-opencode")]' \ ~/.config/opencode/opencode.json > /tmp/oc.json && \ mv /tmp/oc.json ~/.config/opencode/opencode.json ``` @@ -285,11 +287,13 @@ To remove oh-my-opencode: 2. **Remove configuration files (optional)** ```bash - # Remove user config - rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc + # Remove plugin config files recognized during the compatibility window + rm -f ~/.config/opencode/oh-my-openagent.jsonc ~/.config/opencode/oh-my-openagent.json \ + ~/.config/opencode/oh-my-opencode.jsonc ~/.config/opencode/oh-my-opencode.json # Remove project config (if exists) - rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc + rm -f .opencode/oh-my-openagent.jsonc .opencode/oh-my-openagent.json \ + .opencode/oh-my-opencode.jsonc .opencode/oh-my-opencode.json ``` 3. **Verify removal** @@ -315,6 +319,10 @@ See full [Features Documentation](docs/reference/features.md). - **Built-in MCPs**: websearch (Exa), context7 (docs), grep_app (GitHub search) - **Session Tools**: List, read, search, and analyze session history - **Productivity Features**: Ralph Loop, Todo Enforcer, Comment Checker, Think Mode, and more +- **Doctor Command**: Built-in diagnostics (`bunx oh-my-opencode doctor`) verify plugin registration, config, models, and environment +- **Model Fallbacks**: `fallback_models` can mix plain model strings with per-fallback object settings in the same array +- **File Prompts**: Load prompts from files with `file://` support in agent configurations +- **Session Recovery**: Automatic recovery from session errors, context window limits, and API failures - **Model Setup**: Agent-model matching is built into the [Installation Guide](docs/guide/installation.md#step-5-understand-your-model-setup) ## Configuration @@ -324,7 +332,7 @@ Opinionated defaults, adjustable if you insist. See [Configuration Documentation](docs/reference/configuration.md). **Quick Overview:** -- **Config Locations**: `.opencode/oh-my-opencode.jsonc` or `.opencode/oh-my-opencode.json` (project), `~/.config/opencode/oh-my-opencode.jsonc` or `~/.config/opencode/oh-my-opencode.json` (user) +- **Config Locations**: The compatibility layer recognizes both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` plugin config files. Existing installs still commonly use the legacy basename. - **JSONC Support**: Comments and trailing commas supported - **Agents**: Override models, temperatures, prompts, and permissions for any agent - **Built-in Skills**: `playwright` (browser automation), `git-master` (atomic commits) diff --git a/README.ru.md b/README.ru.md index d52d964b6..540643acd 100644 --- a/README.ru.md +++ b/README.ru.md @@ -152,7 +152,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. -**Hephaestus** (`gpt-5.3-codex`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* +**Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. @@ -160,7 +160,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu > Anthropic [заблокировал OpenCode из-за нас.](https://x.com/thdxr/status/2010149530486911014) Именно поэтому Hephaestus зовётся «Законным Мастером». Ирония намеренная. > -> Мы работаем лучше всего на Opus, но Kimi K2.5 + GPT-5.3 Codex уже превосходят ванильный Claude Code. Никакой настройки не требуется. +> Мы работаем лучше всего на Opus, но Kimi K2.5 + GPT-5.4 уже превосходят ванильный Claude Code. Никакой настройки не требуется. ### Оркестрация агентов diff --git a/README.zh-cn.md b/README.zh-cn.md index f0f0bd300..2b2a3ab4c 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -169,7 +169,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 -**Hephaestus** (`gpt-5.3-codex`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* +**Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 @@ -177,7 +177,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu > Anthropic [因为我们屏蔽了 OpenCode](https://x.com/thdxr/status/2010149530486911014)。这就是为什么我们将 Hephaestus 命名为“正牌工匠 (The Legitimate Craftsman)”。这是一个故意的讽刺。 > -> 我们在 Opus 上运行得最好,但仅仅使用 Kimi K2.5 + GPT-5.3 Codex 就足以碾压原版的 Claude Code。完全不需要配置。 +> 我们在 Opus 上运行得最好,但仅仅使用 Kimi K2.5 + GPT-5.4 就足以碾压原版的 Claude Code。完全不需要配置。 ### 智能体调度机制 diff --git a/assets/oh-my-opencode.schema.json b/assets/oh-my-opencode.schema.json index 4324e186c..3ab34f714 100644 --- a/assets/oh-my-opencode.schema.json +++ b/assets/oh-my-opencode.schema.json @@ -4696,6 +4696,27 @@ }, "additionalProperties": false }, + "model_capabilities": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "auto_refresh_on_start": { + "type": "boolean" + }, + "refresh_timeout_ms": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "source_url": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, "openclaw": { "type": "object", "properties": { diff --git a/docs/examples/coding-focused.jsonc b/docs/examples/coding-focused.jsonc new file mode 100644 index 000000000..1eef02602 --- /dev/null +++ b/docs/examples/coding-focused.jsonc @@ -0,0 +1,88 @@ +{ + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json", + + // Optimized for intensive coding sessions. + // Prioritizes deep implementation agents and fast feedback loops. + + "agents": { + // Primary orchestrator: aggressive parallel delegation + "sisyphus": { + "model": "kimi-for-coding/k2p5", + "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.", + }, + + // Heavy lifter: maximum autonomy for coding tasks + "hephaestus": { + "model": "openai/gpt-5.4", + "prompt_append": "You are the primary implementation agent. Own the codebase. Explore, decide, execute. Use LSP and AST-grep aggressively.", + "permission": { "edit": "allow", "bash": { "git": "allow", "test": "allow" } }, + }, + + // Lightweight planner: quick planning for coding tasks + "prometheus": { + "model": "opencode/gpt-5-nano", + "prompt_append": "Keep plans concise. Focus on file structure and key decisions.", + }, + + // Debugging and architecture + "oracle": { "model": "openai/gpt-5.4", "variant": "high" }, + + // Fast docs lookup + "librarian": { "model": "github-copilot/grok-code-fast-1" }, + + // Rapid codebase navigation + "explore": { "model": "github-copilot/grok-code-fast-1" }, + + // Frontend and visual work + "multimodal-looker": { "model": "google/gemini-3.1-pro" }, + + // Plan review: minimal overhead + "metis": { "model": "opencode/gpt-5-nano" }, + + // Code review focus + "momus": { "prompt_append": "Focus on code quality, edge cases, and test coverage." }, + + // Long-running coding sessions + "atlas": {}, + + // Quick fixes and small tasks + "sisyphus-junior": { "model": "opencode/gpt-5-nano" }, + }, + + "categories": { + // Trivial changes: fastest possible + "quick": { "model": "opencode/gpt-5-nano" }, + + // Standard coding tasks: good quality, fast + "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, + + // Complex refactors: best quality + "unspecified-high": { "model": "openai/gpt-5.3-codex" }, + + // Visual work + "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, + + // Deep autonomous work + "deep": { "model": "openai/gpt-5.3-codex" }, + + // Architecture decisions + "ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" }, + }, + + // High concurrency for parallel agent work + "background_task": { + "defaultConcurrency": 8, + "providerConcurrency": { + "anthropic": 5, + "openai": 5, + "google": 10, + "github-copilot": 10, + "opencode": 15, + }, + }, + + // Enable all coding aids + "hashline_edit": true, + "experimental": { "aggressive_truncation": true, "task_system": true }, +} diff --git a/docs/examples/default.jsonc b/docs/examples/default.jsonc new file mode 100644 index 000000000..21ec8df1b --- /dev/null +++ b/docs/examples/default.jsonc @@ -0,0 +1,71 @@ +{ + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json", + + // Balanced defaults for general development. + // Tuned for reliability across diverse tasks without overspending. + + "agents": { + // Main orchestrator: handles delegation and drives tasks to completion + "sisyphus": { + "model": "anthropic/claude-opus-4-6", + "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + }, + + // Deep autonomous worker: end-to-end implementation + "hephaestus": { + "model": "openai/gpt-5.4", + "prompt_append": "Explore thoroughly, then implement. Prefer small, testable changes.", + }, + + // Strategic planner: interview mode before execution + "prometheus": { + "prompt_append": "Always interview first. Validate scope before planning.", + }, + + // Architecture consultant: complex design and debugging + "oracle": { "model": "openai/gpt-5.4", "variant": "high" }, + + // Documentation and code search + "librarian": { "model": "google/gemini-3-flash" }, + + // Fast codebase exploration + "explore": { "model": "github-copilot/grok-code-fast-1" }, + + // Visual tasks: UI/UX, images, diagrams + "multimodal-looker": { "model": "google/gemini-3.1-pro" }, + + // Plan consultant: reviews and improves plans + "metis": {}, + + // Critic and reviewer + "momus": {}, + + // Continuation and long-running task handler + "atlas": {}, + + // Lightweight task executor for simple jobs + "sisyphus-junior": { "model": "opencode/gpt-5-nano" }, + }, + + "categories": { + "quick": { "model": "opencode/gpt-5-nano" }, + "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "writing": { "model": "google/gemini-3-flash" }, + "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, + "deep": { "model": "openai/gpt-5.3-codex" }, + "ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" }, + }, + + // Conservative concurrency for cost control + "background_task": { + "providerConcurrency": { + "anthropic": 3, + "openai": 3, + "google": 5, + "opencode": 10, + }, + }, + + "experimental": { "aggressive_truncation": true }, +} diff --git a/docs/examples/planning-focused.jsonc b/docs/examples/planning-focused.jsonc new file mode 100644 index 000000000..4f6aef926 --- /dev/null +++ b/docs/examples/planning-focused.jsonc @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json", + + // Optimized for strategic planning, architecture, and complex project design. + // Prioritizes deep thinking agents and thorough analysis before execution. + + "agents": { + // Orchestrator: delegates to planning agents first + "sisyphus": { + "model": "anthropic/claude-opus-4-6", + "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.", + }, + + // Implementation: uses planning outputs + "hephaestus": { + "model": "openai/gpt-5.4", + "prompt_append": "Follow established plans precisely. Ask for clarification when plans are ambiguous.", + }, + + // Primary planner: deep interview mode + "prometheus": { + "model": "anthropic/claude-opus-4-6", + "thinking": { "type": "enabled", "budgetTokens": 160000 }, + "prompt_append": "Interview extensively. Question assumptions. Build exhaustive plans with milestones, risks, and contingencies. Use deep & quick agents heavily in parallel for research.", + }, + + // Architecture consultant + "oracle": { + "model": "openai/gpt-5.4", + "variant": "xhigh", + "thinking": { "type": "enabled", "budgetTokens": 120000 }, + }, + + // Research and documentation + "librarian": { "model": "google/gemini-3-flash" }, + + // Exploration for research phase + "explore": { "model": "github-copilot/grok-code-fast-1" }, + + // Visual planning and diagrams + "multimodal-looker": { "model": "google/gemini-3.1-pro", "variant": "high" }, + + // Plan review and refinement: heavily utilized + "metis": { + "model": "anthropic/claude-opus-4-6", + "prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.", + }, + + // Critic: challenges assumptions + "momus": { + "model": "openai/gpt-5.4", + "prompt_append": "Challenge all assumptions in plans. Look for edge cases, failure modes, and overlooked requirements.", + }, + + // Long-running planning sessions + "atlas": { + "prompt_append": "Preserve context across long planning sessions. Track evolving decisions.", + }, + + // Quick research tasks + "sisyphus-junior": { "model": "opencode/gpt-5-nano" }, + }, + + "categories": { + "quick": { "model": "opencode/gpt-5-nano" }, + + "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, + + // High-effort planning tasks: maximum reasoning + "unspecified-high": { + "model": "openai/gpt-5.4", + "variant": "xhigh", + }, + + // Documentation from plans + "writing": { "model": "google/gemini-3-flash" }, + + // Visual architecture + "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, + + // Deep research and analysis + "deep": { "model": "openai/gpt-5.3-codex" }, + + // Strategic reasoning + "ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" }, + + // Creative approaches to problems + "artistry": { "model": "google/gemini-3.1-pro", "variant": "high" }, + }, + + // Moderate concurrency: planning is sequential by nature + "background_task": { + "defaultConcurrency": 5, + "staleTimeoutMs": 300000, + "providerConcurrency": { + "anthropic": 3, + "openai": 3, + }, + "modelConcurrency": { + "anthropic/claude-opus-4-6": 2, + "openai/gpt-5.4": 2, + }, + }, + + "sisyphus_agent": { + "planner_enabled": true, + "replace_plan": true, + }, + + "experimental": { "aggressive_truncation": true }, +} diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index dc95444b2..6f3f65bef 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -27,7 +27,7 @@ Using Sisyphus with older GPT models would be like taking your best project mana Hephaestus is the developer who stays in their room coding all day. Doesn't talk much. Might seem socially awkward. But give them a hard technical problem and they'll emerge three hours later with a solution nobody else could have found. -**This is why Hephaestus uses GPT-5.3 Codex.** Codex is built for exactly this: +**This is why Hephaestus uses GPT-5.4.** GPT-5.4 is built for exactly this: - Deep, autonomous exploration without hand-holding - Multi-file reasoning across complex codebases @@ -82,7 +82,7 @@ These agents are built for GPT's principle-driven style. Their prompts assume au | Agent | Role | Fallback Chain | Notes | | -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ | -| **Hephaestus** | Autonomous deep worker | GPT-5.3 Codex → GPT-5.4 (Copilot) | Requires GPT access. GPT-5.4 via Copilot as fallback. The craftsman. | +| **Hephaestus** | Autonomous deep worker | GPT-5.4 | Requires GPT access. The craftsman. | | **Oracle** | Architecture consultant | GPT-5.4 → Gemini 3.1 Pro → Claude Opus → opencode-go/glm-5 | Read-only high-IQ consultation. | | **Momus** | Ruthless reviewer | GPT-5.4 → Claude Opus → Gemini 3.1 Pro → opencode-go/glm-5 | Verification and plan review. GPT-5.4 uses xhigh variant. | @@ -92,10 +92,10 @@ These agents do grep, search, and retrieval. They intentionally use the fastest, | Agent | Role | Fallback Chain | Notes | | --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- | -| **Explore** | Fast codebase grep | Grok Code Fast → opencode-go/minimax-m2.5 → MiniMax Free → Haiku → GPT-5-Nano | Speed is everything. Fire 10 in parallel. | -| **Librarian** | Docs/code search | opencode-go/minimax-m2.5 → MiniMax Free → Haiku → GPT-5-Nano | Doc retrieval doesn't need deep reasoning. | -| **Multimodal Looker** | Vision/screenshots | GPT-5.4 → opencode-go/kimi-k2.5 → GLM-4.6v → GPT-5-Nano | Uses the first available multimodal-capable fallback. | -| **Sisyphus-Junior** | Category executor | Claude Sonnet → opencode-go/kimi-k2.5 → GPT-5.4 → Big Pickle | Handles delegated category tasks. Sonnet-tier default. | +| **Explore** | Fast codebase grep | Grok Code Fast → opencode-go/minimax-m2.7 → opencode/minimax-m2.5 → Haiku → GPT-5-Nano | Speed is everything. Fire 10 in parallel. | +| **Librarian** | Docs/code search | opencode-go/minimax-m2.7 → opencode/minimax-m2.5 → Haiku → GPT-5-Nano | Doc retrieval doesn't need deep reasoning. | +| **Multimodal Looker** | Vision/screenshots | GPT-5.4 → opencode-go/kimi-k2.5 → GLM-4.6v → GPT-5-Nano | Uses the first available multimodal-capable fallback. | +| **Sisyphus-Junior** | Category executor | Claude Sonnet → opencode-go/kimi-k2.5 → GPT-5.4 → MiniMax M2.7 → Big Pickle | Handles delegated category tasks. Sonnet-tier default. | --- @@ -119,7 +119,7 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents | Model | Strengths | | ----------------- | ----------------------------------------------------------------------------------------------- | -| **GPT-5.3 Codex** | Deep coding powerhouse. Autonomous exploration. Required for Hephaestus. | +| **GPT-5.3 Codex** | Deep coding powerhouse. Autonomous exploration. Still available for deep category and explicit overrides. | | **GPT-5.4** | High intelligence, strategic reasoning. Default for Oracle, Momus, and a key fallback for Prometheus / Atlas. Uses xhigh variant for Momus. | | **GPT-5.4 Mini** | Fast + strong reasoning. Good for lightweight autonomous tasks. Default for quick category. | | **GPT-5-Nano** | Ultra-cheap, fast. Good for simple utility tasks. | @@ -131,7 +131,8 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents | **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. | | **Gemini 3 Flash** | Fast. Good for doc search and light tasks. | | **Grok Code Fast 1** | Blazing fast code grep. Default for Explore agent. | -| **MiniMax M2.5** | Fast and smart. Good for utility tasks and search/retrieval. | +| **MiniMax M2.7** | Fast and smart. Used where provider catalogs expose the newer MiniMax line, especially through OpenCode Go. | +| **MiniMax M2.7 Highspeed** | Ultra-fast variant. You may still see it in older docs, logs, or provider catalogs during the transition. | ### OpenCode Go @@ -143,11 +144,11 @@ A premium subscription tier ($10/month) that provides reliable access to Chinese | ------------------------ | --------------------------------------------------------------------- | | **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. | | **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. | -| **opencode-go/minimax-m2.5** | Ultra-cheap, fast responses. Used by Librarian, Explore for utility work. | +| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Librarian, Explore, Atlas, and Sisyphus-Junior for utility work. | **When It Gets Used:** -OpenCode Go models appear in fallback chains as intermediate options. They bridge the gap between premium Claude access and free-tier alternatives. The system tries OpenCode Go models before falling back to free tiers (MiniMax Free, Big Pickle) or GPT alternatives. +OpenCode Go models appear in fallback chains as intermediate options. They bridge the gap between premium Claude access and free-tier alternatives. The system tries OpenCode Go models before falling back to cheaper provider-specific entries like MiniMax or Big Pickle, then GPT alternatives where applicable. **Go-Only Scenarios:** @@ -155,7 +156,7 @@ Some model identifiers like `k2p5` (paid Kimi K2.5) and `glm-5` may only be avai ### About Free-Tier Fallbacks -You may see model names like `kimi-k2.5-free`, `minimax-m2.5-free`, or `big-pickle` (GLM 4.6) in the source code or logs. These are free-tier versions of the same model families, served through the OpenCode Zen provider. They exist as lower-priority entries in fallback chains. +You may see model names like `kimi-k2.5-free`, `minimax-m2.7`, `minimax-m2.5`, or `big-pickle` (GLM 4.6) in the source code or logs. These are provider-specific or speed-optimized entries in fallback chains. The exact MiniMax model can differ by provider catalog. You don't need to configure them. The system includes them so it degrades gracefully when you don't have every paid subscription. If you have the paid version, the paid version is always preferred. @@ -171,7 +172,7 @@ When agents delegate work, they don't pick a model name — they pick a **catego | `ultrabrain` | Maximum reasoning needed | GPT-5.4 → Gemini 3.1 Pro → Claude Opus → opencode-go/glm-5 | | `deep` | Deep coding, complex logic | GPT-5.3 Codex → Claude Opus → Gemini 3.1 Pro | | `artistry` | Creative, novel approaches | Gemini 3.1 Pro → Claude Opus → GPT-5.4 | -| `quick` | Simple, fast tasks | GPT-5.4 Mini → Claude Haiku → Gemini Flash → opencode-go/minimax-m2.5 → GPT-5-Nano | +| `quick` | Simple, fast tasks | GPT-5.4 Mini → Claude Haiku → Gemini Flash → opencode-go/minimax-m2.7 → GPT-5-Nano | | `unspecified-high` | General complex work | Claude Opus → GPT-5.4 → GLM 5 → K2P5 → opencode-go/glm-5 → Kimi K2.5 | | `unspecified-low` | General standard work | Claude Sonnet → GPT-5.3 Codex → opencode-go/kimi-k2.5 → Gemini Flash | | `writing` | Text, docs, prose | Gemini Flash → opencode-go/kimi-k2.5 → Claude Sonnet | @@ -186,7 +187,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch ```jsonc { - "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json", + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { // Main orchestrator: Claude Opus or Kimi K2.5 work best @@ -254,7 +255,15 @@ Run `opencode models` to see available models, `opencode auth login` to authenti ### How Model Resolution Works -Each agent has a fallback chain. The system tries models in priority order until it finds one available through your connected providers. You don't need to configure providers per model — just authenticate (`opencode auth login`) and the system figures out which models are available and where. +Each agent has a fallback chain. The system tries models in priority order until it finds one available through your connected providers. You don't need to configure providers per model. Just authenticate (`opencode auth login`) and the system figures out which models are available and where. + +Core-agent tab cycling is now deterministic. The fixed priority order is Sisyphus, Hephaestus, Prometheus, and Atlas, then the remaining agents follow. + +Your explicit configuration always wins. If you set a specific model for an agent, that choice takes precedence even when resolution data is cold. + +Variant and `reasoningEffort` overrides are normalized to model-supported values, so cross-provider overrides degrade gracefully instead of failing hard. + +To see which models your agents will actually use, run `bunx oh-my-opencode doctor`. This shows effective model resolution based on your current authentication and config. ``` Agent Request → User Override (if configured) → Fallback Chain → System Default diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 06722a352..0b92929cf 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -5,7 +5,7 @@ Paste this into your llm agent session: ``` -Install and configure oh-my-openagent by following the instructions here: +Install and configure oh-my-opencode by following the instructions here: https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md ``` @@ -14,8 +14,8 @@ https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/do Run the interactive installer: ```bash -bunx oh-my-openagent install # recommended -npx oh-my-openagent install # alternative +bunx oh-my-opencode install # recommended +npx oh-my-opencode install # alternative ``` > **Note**: The CLI ships with standalone binaries for all major platforms. No runtime (Bun/Node.js) is required for CLI execution after installation. @@ -26,6 +26,8 @@ Follow the prompts to configure your Claude, ChatGPT, and Gemini subscriptions. After you install it, you can read this [overview guide](./overview.md) to understand more. +The published package and local binary are still `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config loading recognizes both `oh-my-openagent.json[c]` and `oh-my-opencode.json[c]` during the transition. + ## For LLM Agents > **IMPORTANT: Use `curl` to fetch this file, NOT WebFetch.** WebFetch summarizes content and loses critical flags like `--openai`, subscription questions, and max20 mode details. Always use: @@ -34,7 +36,7 @@ After you install it, you can read this [overview guide](./overview.md) to under > curl -fsSL https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md > ``` -If you're an LLM Agent helping set up oh-my-openagent, Welcome! You'll now help your user to install the best agent harness, OhMyOpenAgent. Tell user this with greetings, with test 'oMoMoMoMo...' +If you're an LLM Agent helping set up oh-my-opencode, welcome. You'll help your user install the harness and verify the rename-compat setup cleanly. Tell user this with greetings, with text 'oMoMoMoMo...' follow these steps: @@ -69,7 +71,7 @@ Ask the user these questions to determine CLI options: - If **no** → `--zai-coding-plan=no` (default) 7. **Do you have an OpenCode Go subscription?** - - OpenCode Go is a $10/month subscription providing access to GLM-5, Kimi K2.5, and MiniMax M2.5 models + - OpenCode Go is a $10/month subscription providing access to GLM-5, Kimi K2.5, and MiniMax M2.7 models - If **yes** → `--opencode-go=yes` - If **no** → `--opencode-go=no` (default) @@ -96,19 +98,19 @@ Spawn a subagent to handle installation and report back - to save context. Based on user's answers, run the CLI installer with appropriate flags: ```bash -bunx oh-my-openagent install --no-tui --claude= --gemini= --copilot= [--openai=] [--opencode-go=] [--opencode-zen=] [--zai-coding-plan=] +bunx oh-my-opencode install --no-tui --claude= --gemini= --copilot= [--openai=] [--opencode-go=] [--opencode-zen=] [--zai-coding-plan=] ``` **Examples:** -- User has all native subscriptions: `bunx oh-my-openagent install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no` -- User has only Claude: `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no` -- User has Claude + OpenAI: `bunx oh-my-openagent install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no` -- User has only GitHub Copilot: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=yes` -- User has Z.ai for Librarian: `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes` -- User has only OpenCode Zen: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes` -- User has OpenCode Go only: `bunx oh-my-openagent install --no-tui --claude=no --openai=no --gemini=no --copilot=no --opencode-go=yes` -- User has no subscriptions: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no` +- User has all native subscriptions: `bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no` +- User has only Claude: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no` +- User has Claude + OpenAI: `bunx oh-my-opencode install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no` +- User has only GitHub Copilot: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes` +- User has Z.ai for Librarian: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes` +- User has only OpenCode Zen: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes` +- User has OpenCode Go only: `bunx oh-my-opencode install --no-tui --claude=no --openai=no --gemini=no --copilot=no --opencode-go=yes` +- User has no subscriptions: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no` The CLI will: @@ -120,8 +122,17 @@ The CLI will: ```bash opencode --version # Should be 1.0.150 or higher -cat ~/.config/opencode/opencode.json # Should contain "oh-my-openagent" in plugin array +cat ~/.config/opencode/opencode.json # Should contain "oh-my-openagent" in plugin array, or the legacy "oh-my-opencode" entry while you are still migrating ``` +#### Run Doctor Verification + +After installation, verify everything is working correctly: + +```bash +bunx oh-my-opencode doctor +``` + +This checks your environment, authentication status, and shows which models each agent will actually use. ### Step 4: Configure Authentication @@ -154,9 +165,9 @@ First, add the opencode-antigravity-auth plugin: You'll also need full model settings in `opencode.json`. Read the [opencode-antigravity-auth documentation](https://github.com/NoeFabris/opencode-antigravity-auth), copy the full model configuration from the README, and merge carefully to avoid breaking the user's existing setup. The plugin now uses a **variant system** — models like `antigravity-gemini-3-pro` support `low`/`high` variants instead of separate `-low`/`-high` model entries. -##### oh-my-openagent Agent Model Override +##### Plugin config model override -The `opencode-antigravity-auth` plugin uses different model names than the built-in Google auth. Override the agent models in `oh-my-openagent.json` (or `.opencode/oh-my-openagent.json`): +The `opencode-antigravity-auth` plugin uses different model names than the built-in Google auth. Override the agent models in your plugin config file. Existing installs still commonly use `oh-my-opencode.json` or `.opencode/oh-my-opencode.json`, while the compatibility layer also recognizes `oh-my-openagent.json[c]`. ```json { @@ -201,7 +212,7 @@ GitHub Copilot is supported as a **fallback provider** when native providers are ##### Model Mappings -When GitHub Copilot is the best available provider, oh-my-openagent uses these model assignments: +When GitHub Copilot is the best available provider, the compatibility layer resolves these assignments: | Agent | Model | | ------------- | --------------------------------- | @@ -227,23 +238,22 @@ If Z.ai is your main provider, the most important fallbacks are: #### OpenCode Zen -OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, and `opencode/minimax-m2.5-free`. +OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, and `opencode/minimax-m2.5`. -When OpenCode Zen is the best available provider (no native or Copilot), these models are used: +When OpenCode Zen is the best available provider, these are the most relevant source-backed examples: | Agent | Model | | ------------- | ---------------------------------------------------- | | **Sisyphus** | `opencode/claude-opus-4-6` | | **Oracle** | `opencode/gpt-5.4` | -| **Explore** | `opencode/gpt-5-nano` | -| **Librarian** | `opencode/minimax-m2.5-free` / `opencode/big-pickle` | +| **Explore** | `opencode/claude-haiku-4-5` | ##### Setup Run the installer and select "Yes" for GitHub Copilot: ```bash -bunx oh-my-openagent install +bunx oh-my-opencode install # Select your subscriptions (Claude, ChatGPT, Gemini) # When prompted: "Do you have a GitHub Copilot subscription?" → Select "Yes" ``` @@ -251,7 +261,7 @@ bunx oh-my-openagent install Or use non-interactive mode: ```bash -bunx oh-my-openagent install --no-tui --claude=no --openai=no --gemini=no --copilot=yes +bunx oh-my-opencode install --no-tui --claude=no --openai=no --gemini=no --copilot=yes ``` Then authenticate with GitHub: @@ -263,7 +273,7 @@ opencode auth login ### Step 5: Understand Your Model Setup -You've just configured oh-my-openagent. Here's what got set up and why. +You've just configured oh-my-opencode. Here's what got set up and why. #### Model Families: What You're Working With @@ -285,7 +295,7 @@ Not all models behave the same way. Understanding which models are "similar" hel | Model | Provider(s) | Notes | | ----------------- | -------------------------------- | ------------------------------------------------- | -| **GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse. Required for Hephaestus. | +| **GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse. Still available for deep category and explicit overrides. | | **GPT-5.4** | openai, github-copilot, opencode | High intelligence. Default for Oracle. | | **GPT-5.4 Mini** | openai, github-copilot, opencode | Fast + strong reasoning. Default for quick category. | | **GPT-5-Nano** | opencode | Ultra-cheap, fast. Good for simple utility tasks. | @@ -296,8 +306,8 @@ Not all models behave the same way. Understanding which models are "similar" hel | --------------------- | -------------------------------- | ----------------------------------------------------------- | | **Gemini 3.1 Pro** | google, github-copilot, opencode | Excels at visual/frontend tasks. Different reasoning style. | | **Gemini 3 Flash** | google, github-copilot, opencode | Fast, good for doc search and light tasks. | -| **MiniMax M2.5** | venice | Fast and smart. Good for utility tasks. | -| **MiniMax M2.5 Free** | opencode | Free-tier MiniMax. Fast for search/retrieval. | +| **MiniMax M2.7** | venice, opencode-go | Fast and smart. Good for utility tasks where the provider catalog exposes M2.7. | +| **MiniMax M2.5** | opencode | Legacy OpenCode catalog entry still used in some fallback chains for compatibility. | **Speed-Focused Models**: @@ -305,7 +315,7 @@ Not all models behave the same way. Understanding which models are "similar" hel | ----------------------- | ---------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | **Grok Code Fast 1** | github-copilot, venice | Very fast | Optimized for code grep/search. Default for Explore. | | **Claude Haiku 4.5** | anthropic, opencode | Fast | Good balance of speed and intelligence. | -| **MiniMax M2.5 (Free)** | opencode, venice | Fast | Smart for its speed class. | +| **MiniMax M2.5** | opencode | Very fast | Legacy OpenCode catalog entry that still appears in some utility fallback chains. | | **GPT-5.3-codex-spark** | openai | Extremely fast | Blazing fast but compacts so aggressively that oh-my-openagent's context management doesn't work well with it. Not recommended for omo agents. | #### What Each Agent Does and Which Model It Got @@ -316,7 +326,7 @@ Based on your subscriptions, here's how the agents were configured: | Agent | Role | Default Chain | What It Does | | ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- | -| **Sisyphus** | Main ultraworker | Opus (max) → Kimi K2.5 → GLM 5 → Big Pickle | Primary coding agent. Orchestrates everything. **Never use GPT — no GPT prompt exists.** | +| **Sisyphus** | Main ultraworker | Opus (max) → Kimi K2.5 → GPT-5.4 → GLM 5 → Big Pickle | Primary coding agent. Orchestrates everything. Claude-family models are still preferred, but GPT-5.4 now has a dedicated prompt path. | | **Metis** | Plan review | Opus (max) → Kimi K2.5 → GPT-5.4 → Gemini 3.1 Pro | Reviews Prometheus plans for gaps. | **Dual-Prompt Agents** (auto-switch between Claude and GPT prompts): @@ -328,13 +338,13 @@ Priority: **Claude > GPT > Claude-like models** | Agent | Role | Default Chain | GPT Prompt? | | -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- | | **Prometheus** | Strategic planner | Opus (max) → **GPT-5.4 (high)** → Kimi K2.5 → Gemini 3.1 Pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | -| **Atlas** | Todo orchestrator | **Kimi K2.5** → Sonnet → GPT-5.4 | Yes — GPT-optimized todo management | +| **Atlas** | Todo orchestrator | **Claude Sonnet 4.6** → Kimi K2.5 → GPT-5.4 | Yes - GPT-optimized todo management | **GPT-Native Agents** (built for GPT, don't override to Claude): | Agent | Role | Default Chain | Notes | | -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ | -| **Hephaestus** | Deep autonomous worker | GPT-5.3-codex (medium) only | "Codex on steroids." No fallback. Requires GPT access. | +| **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. | | **Oracle** | Architecture/debugging | GPT-5.4 (high) → Gemini 3.1 Pro → Opus | High-IQ strategic backup. GPT preferred. | | **Momus** | High-accuracy reviewer | GPT-5.4 (medium) → Opus → Gemini 3.1 Pro | Verification agent. GPT preferred. | @@ -344,9 +354,9 @@ These agents do search, grep, and retrieval. They intentionally use fast, cheap | Agent | Role | Default Chain | Design Rationale | | --------------------- | ------------------ | ---------------------------------------------------------------------- | -------------------------------------------------------------- | -| **Explore** | Fast codebase grep | MiniMax M2.5 Free → Grok Code Fast → MiniMax M2.5 → Haiku → GPT-5-Nano | Speed is everything. Grok is blazing fast for grep. | -| **Librarian** | Docs/code search | MiniMax M2.5 Free → Gemini Flash → Big Pickle | Entirely free-tier. Doc retrieval doesn't need deep reasoning. | -| **Multimodal Looker** | Vision/screenshots | Kimi K2.5 → Kimi Free → Gemini Flash → GPT-5.4 → GLM-4.6v | Kimi excels at multimodal understanding. | +| **Explore** | Fast codebase grep | Grok Code Fast → OpenCode Go MiniMax M2.7 → OpenCode MiniMax M2.5 → Haiku → GPT-5-Nano | Speed is everything. Grok is blazing fast for grep. | +| **Librarian** | Docs/code search | OpenCode Go MiniMax M2.7 → OpenCode MiniMax M2.5 → Haiku → GPT-5-Nano | Doc retrieval doesn't need deep reasoning. MiniMax is fast where the provider catalog supports it. | +| **Multimodal Looker** | Vision/screenshots | GPT-5.4 → Kimi K2.5 → GLM-4.6v → GPT-5-Nano | GPT-5.4 now leads the default vision path when available. | #### Why Different Models Need Different Prompts @@ -365,7 +375,7 @@ This is why Prometheus and Atlas ship separate prompts per model family — they #### Custom Model Configuration -If the user wants to override which model an agent uses, you can customize in `oh-my-openagent.json`: +If the user wants to override which model an agent uses, you can customize in your plugin config file. Existing installs still commonly use `oh-my-opencode.json`, while the compatibility layer also recognizes `oh-my-openagent.json[c]`. ```jsonc { @@ -400,7 +410,7 @@ GPT (5.3-codex, 5.2) > Claude Opus (decent fallback) > Gemini (acceptable) **Dangerous** (no prompt support): -- Sisyphus → GPT: **No GPT prompt. Will degrade significantly.** +- Sisyphus → older GPT models: **Still a bad fit. GPT-5.4 is the only dedicated GPT prompt path.** - Hephaestus → Claude: **Built for Codex. Claude can't replicate this.** - Explore → Opus: **Massive cost waste. Explore needs speed, not intelligence.** - Librarian → Opus: **Same. Doc search doesn't need Opus-level reasoning.** @@ -462,3 +472,7 @@ Tell the user of following: 4. You wanna have your own agent- catalog setup? I can read the [docs](docs/guide/agent-model-matching.md) and set up for you after interviewing! That's it. The agent will figure out the rest and handle everything automatically. + +#### Advanced Configuration + +You can customize agent models and fallback chains in your config. The `fallback_models` field accepts either a single string or an array that mixes strings and per-model objects with settings like `variant` and `temperature`. See the [Configuration Reference](../reference/configuration.md) and example configs in `docs/examples/` for details. diff --git a/docs/guide/orchestration.md b/docs/guide/orchestration.md index 44ef65ca9..edc0dc8e3 100644 --- a/docs/guide/orchestration.md +++ b/docs/guide/orchestration.md @@ -420,7 +420,7 @@ Atlas is automatically activated when you run `/start-work`. You don't need to m | Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` | | --------------- | ------------------------------------------ | ---------------------------------------------------- | -| **Model** | GPT-5.3 Codex (medium reasoning) | Claude Opus 4.6 / GPT-5.4 / GLM 5 depending on setup | +| **Model** | GPT-5.4 (medium reasoning) | Claude Opus 4.6 / GPT-5.4 / GLM 5 depending on setup | | **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode | | **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios | | **Planning** | Self-plans during execution | Uses Prometheus plans if available | @@ -443,8 +443,8 @@ Switch to Hephaestus (Tab → Select Hephaestus) when: - "Integrate our Rust core with the TypeScript frontend" - "Migrate from MongoDB to PostgreSQL with zero downtime" -4. **You specifically want GPT-5.3 Codex reasoning** - - Some problems benefit from GPT-5.3 Codex's training characteristics +4. **You specifically want GPT-5.4 reasoning** + - Some problems benefit from GPT-5.4's training characteristics **When to Use Sisyphus + `ulw`:** @@ -469,7 +469,7 @@ Use the `ulw` keyword in Sisyphus when: **Recommendation:** - **For most users**: Use `ulw` keyword in Sisyphus. It's the default path and works excellently for 90% of complex tasks. -- **For power users**: Switch to Hephaestus when you specifically need GPT-5.3 Codex's reasoning style or want the "AmpCode deep mode" experience of fully autonomous exploration and execution. +- **For power users**: Switch to Hephaestus when you specifically need GPT-5.4's reasoning style or want the "AmpCode deep mode" experience of fully autonomous exploration and execution. --- @@ -520,7 +520,7 @@ Type `exit` or start a new session. Atlas is primarily entered via `/start-work` **For most tasks**: Type `ulw` in Sisyphus. -**Use Hephaestus when**: You specifically need GPT-5.3 Codex's reasoning style for deep architectural work or complex debugging. +**Use Hephaestus when**: You specifically need GPT-5.4's reasoning style for deep architectural work or complex debugging. --- diff --git a/docs/guide/overview.md b/docs/guide/overview.md index a185c9189..9ccf5bc4d 100644 --- a/docs/guide/overview.md +++ b/docs/guide/overview.md @@ -93,9 +93,9 @@ Sisyphus still works best on Claude-family models, Kimi, and GLM. GPT-5.4 now ha Named with intentional irony. Anthropic blocked OpenCode from using their API because of this project. So the team built an autonomous GPT-native agent instead. -Hephaestus runs on GPT-5.3 Codex. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. He is the legitimate craftsman because he was born from necessity, not privilege. +Hephaestus runs on GPT-5.4. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. He is the legitimate craftsman because he was born from necessity, not privilege. -Use Hephaestus when you need deep architectural reasoning, complex debugging across many files, or cross-domain knowledge synthesis. Switch to him explicitly when the work demands GPT-5.3 Codex's particular strengths. +Use Hephaestus when you need deep architectural reasoning, complex debugging across many files, or cross-domain knowledge synthesis. Switch to him explicitly when the work demands GPT-5.4's particular strengths. **Why this beats vanilla Codex CLI:** @@ -214,14 +214,13 @@ You can override specific agents or categories in your config: **GPT models** (explicit reasoning, principle-driven): -- GPT-5.3-codex — deep coding powerhouse, required for Hephaestus -- GPT-5.4 — high intelligence, default for Oracle +- GPT-5.4 — deep coding powerhouse, required for Hephaestus and default for Oracle - GPT-5-Nano — ultra-cheap, fast utility tasks **Different-behavior models**: - Gemini 3.1 Pro — excels at visual/frontend tasks -- MiniMax M2.5 — fast and smart for utility tasks +- MiniMax M2.7 / M2.7-highspeed — fast and smart for utility tasks - Grok Code Fast 1 — optimized for code grep/search See the [Agent-Model Matching Guide](./agent-model-matching.md) for complete details on which models work best for each agent, safe vs dangerous overrides, and provider priority chains. diff --git a/docs/model-capabilities-maintenance.md b/docs/model-capabilities-maintenance.md new file mode 100644 index 000000000..4f6d6bbce --- /dev/null +++ b/docs/model-capabilities-maintenance.md @@ -0,0 +1,33 @@ +# Model Capabilities Maintenance + +This project treats model capability resolution as a layered system: + +1. runtime metadata from connected providers +2. `models.dev` bundled/runtime snapshot data +3. explicit compatibility aliases +4. heuristic fallback as the last resort + +## Internal policy + +- Built-in OmO agent/category requirement models must use canonical model IDs. +- Aliases exist only to preserve compatibility with historical OmO names or provider-specific decorations. +- New decorated names like `-high`, `-low`, or `-thinking` should not be added to built-in requirements when a canonical model ID plus structured settings can express the same thing. +- If a provider or config input still uses an alias, normalize it at the edge and continue internally with the canonical ID. + +## When adding an alias + +- Add the alias rule to `src/shared/model-capability-aliases.ts`. +- Include a rationale for why the alias exists. +- Add or update tests so the alias is covered explicitly. +- Ensure the alias canonical target exists in the bundled `models.dev` snapshot. + +## Guardrails + +`bun run test:model-capabilities` enforces the following invariants: + +- exact alias targets must exist in the bundled snapshot +- exact alias keys must not silently become canonical `models.dev` IDs +- pattern aliases must not rewrite canonical snapshot IDs +- built-in requirement models must stay canonical and snapshot-backed + +The scheduled `refresh-model-capabilities` workflow runs these guardrails before opening an automated snapshot refresh PR. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 2d47a59ce..e467ae526 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -1,15 +1,15 @@ # CLI Reference -Complete reference for the `oh-my-openagent` command-line interface. +Complete reference for the published `oh-my-opencode` CLI. During the rename transition, OpenCode plugin registration now prefers `oh-my-openagent` inside `opencode.json`. ## Basic Usage ```bash # Display help -bunx oh-my-openagent +bunx oh-my-opencode # Or with npx -npx oh-my-openagent +npx oh-my-opencode ``` ## Commands @@ -27,20 +27,20 @@ npx oh-my-openagent ## install -Interactive installation tool for initial Oh-My-OpenAgent setup. Provides a TUI based on `@clack/prompts`. +Interactive installation tool for initial Oh My OpenCode setup. Provides a TUI based on `@clack/prompts`. ### Usage ```bash -bunx oh-my-openagent install +bunx oh-my-opencode install ``` ### Installation Process 1. **Provider Selection**: Choose your AI provider (Claude, ChatGPT, or Gemini) 2. **API Key Input**: Enter the API key for your selected provider -3. **Configuration File Creation**: Generates `opencode.json` or `oh-my-openagent.json` files -4. **Plugin Registration**: Automatically registers the oh-my-openagent plugin in OpenCode settings +3. **Configuration File Creation**: Writes the plugin config file used by the current install path. Existing installs still commonly use `oh-my-opencode.json`, while renamed `oh-my-openagent.json[c]` files are also recognized. +4. **Plugin Registration**: Registers `oh-my-openagent` in OpenCode settings, or upgrades a legacy `oh-my-opencode` entry during the compatibility window ### Options @@ -53,12 +53,18 @@ bunx oh-my-openagent install ## doctor -Diagnoses your environment to ensure Oh-My-OpenAgent is functioning correctly. Performs 17+ health checks. +Diagnoses your environment to ensure Oh My OpenCode is functioning correctly. Performs 17+ health checks covering installation, configuration, authentication, dependencies, and tools. +The doctor command detects common issues including: +- Legacy plugin entry references in `opencode.json` (warns when `oh-my-opencode` is still used instead of `oh-my-openagent`) +- Configuration file validity and JSONC parsing errors +- Model resolution and fallback chain verification +- API key validity for configured providers +- Missing or misconfigured MCP servers ### Usage ```bash -bunx oh-my-openagent doctor +bunx oh-my-opencode doctor ``` ### Diagnostic Categories @@ -83,7 +89,7 @@ bunx oh-my-openagent doctor ### Example Output ``` -oh-my-openagent doctor +oh-my-opencode doctor ┌──────────────────────────────────────────────────┐ │ Oh-My-OpenAgent Doctor │ @@ -94,7 +100,8 @@ Installation ✓ Plugin registered in opencode.json Configuration - ✓ oh-my-openagent.json is valid + ✓ oh-my-opencode.jsonc is valid + ✓ Model resolution: all agents have valid fallback chains ⚠ categories.visual-engineering: using default model Authentication @@ -109,7 +116,6 @@ Dependencies Summary: 10 passed, 1 warning, 1 failed ``` - --- ## run @@ -119,7 +125,7 @@ Executes OpenCode sessions and monitors task completion. ### Usage ```bash -bunx oh-my-openagent run [prompt] +bunx oh-my-opencode run [prompt] ``` ### Options @@ -148,16 +154,16 @@ Manages OAuth 2.1 authentication for remote MCP servers. ```bash # Login to an OAuth-protected MCP server -bunx oh-my-openagent mcp oauth login --server-url https://api.example.com +bunx oh-my-opencode mcp oauth login --server-url https://api.example.com # Login with explicit client ID and scopes -bunx oh-my-openagent mcp oauth login my-api --server-url https://api.example.com --client-id my-client --scopes "read,write" +bunx oh-my-opencode mcp oauth login my-api --server-url https://api.example.com --client-id my-client --scopes "read,write" # Remove stored OAuth tokens -bunx oh-my-openagent mcp oauth logout +bunx oh-my-opencode mcp oauth logout # Check OAuth token status -bunx oh-my-openagent mcp oauth status [server-name] +bunx oh-my-opencode mcp oauth status [server-name] ``` ### Options @@ -178,8 +184,18 @@ Tokens are stored in `~/.config/opencode/mcp-oauth.json` with `0600` permissions The CLI searches for configuration files in the following locations (in priority order): -1. **Project Level**: `.opencode/oh-my-openagent.json` -2. **User Level**: `~/.config/opencode/oh-my-openagent.json` +1. **Project Level**: `.opencode/oh-my-openagent.jsonc`, `.opencode/oh-my-openagent.json`, `.opencode/oh-my-opencode.jsonc`, or `.opencode/oh-my-opencode.json` +2. **User Level**: `~/.config/opencode/oh-my-openagent.jsonc`, `~/.config/opencode/oh-my-openagent.json`, `~/.config/opencode/oh-my-opencode.jsonc`, or `~/.config/opencode/oh-my-opencode.json` + +**Naming Note**: The published package and binary are still `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`. Plugin config loading recognizes both `oh-my-openagent.*` and legacy `oh-my-opencode.*` basenames. If both basenames exist in the same directory, the legacy `oh-my-opencode.*` file currently wins. + +### Filename Compatibility + +Both `.jsonc` and `.json` extensions are supported. JSONC (JSON with Comments) is preferred as it allows: +- Comments (both `//` and `/* */` styles) +- Trailing commas in arrays and objects + +If both `.jsonc` and `.json` exist in the same directory, the `.jsonc` file takes precedence. ### JSONC Support @@ -219,31 +235,40 @@ bun install -g opencode@latest ```bash # Reinstall plugin -bunx oh-my-openagent install +bunx oh-my-opencode install ``` ### Doctor Check Failures ```bash # Diagnose with detailed information -bunx oh-my-openagent doctor --verbose +bunx oh-my-opencode doctor --verbose # Check specific category only -bunx oh-my-openagent doctor --category authentication +bunx oh-my-opencode doctor --category authentication ``` +### "Using legacy package name" Warning + +The doctor warns if it finds the legacy plugin entry `oh-my-opencode` in `opencode.json`. Update the plugin array to the canonical `oh-my-openagent` entry: + +```bash +# Replace the legacy plugin entry in user config +jq '.plugin = (.plugin // [] | map(if . == "oh-my-opencode" then "oh-my-openagent" else . end))' \ + ~/.config/opencode/opencode.json > /tmp/opencode.json && mv /tmp/opencode.json ~/.config/opencode/opencode.json +``` --- ## Non-Interactive Mode -Use the `--no-tui` option for CI/CD environments. +Use JSON output for CI or scripted diagnostics. ```bash # Run doctor in CI environment -bunx oh-my-openagent doctor --no-tui --json +bunx oh-my-opencode doctor --json # Save results to file -bunx oh-my-openagent doctor --json > doctor-report.json +bunx oh-my-opencode doctor --json > doctor-report.json ``` --- diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index ab956b4ed..7b5de6133 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -1,6 +1,6 @@ # Configuration Reference -Complete reference for `oh-my-openagent.jsonc` configuration. This document covers every available option with examples. +Complete reference for Oh My OpenCode plugin configuration. During the rename transition, the runtime recognizes both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` files. --- @@ -42,27 +42,28 @@ Complete reference for `oh-my-openagent.jsonc` configuration. This document cove ### File Locations -Priority order (project overrides user): +User config is loaded first, then project config overrides it. In each directory, the compatibility layer recognizes both the renamed and legacy basenames. -1. `.opencode/oh-my-openagent.jsonc` / `.opencode/oh-my-openagent.json` +1. Project config: `.opencode/oh-my-openagent.json[c]` or `.opencode/oh-my-opencode.json[c]` 2. User config (`.jsonc` preferred over `.json`): -| Platform | Path | -| ----------- | ----------------------------------------- | -| macOS/Linux | `~/.config/opencode/oh-my-openagent.jsonc` | -| Windows | `%APPDATA%\opencode\oh-my-openagent.jsonc` | +| Platform | Path candidates | +| ----------- | --------------- | +| macOS/Linux | `~/.config/opencode/oh-my-openagent.json[c]`, `~/.config/opencode/oh-my-opencode.json[c]` | +| Windows | `%APPDATA%\opencode\oh-my-openagent.json[c]`, `%APPDATA%\opencode\oh-my-opencode.json[c]` | +**Rename compatibility:** OpenCode plugin registration now prefers `oh-my-openagent`, while legacy `oh-my-opencode` entries and config basenames still load during the transition. If both plugin config basenames exist in the same directory, the legacy `oh-my-opencode.*` file currently wins. JSONC supports `// line comments`, `/* block comments */`, and trailing commas. Enable schema autocomplete: ```json { - "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json" + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json" } ``` -Run `bunx oh-my-openagent install` for guided setup. Run `opencode models` to list available models. +Run `bunx oh-my-opencode install` for guided setup. Run `opencode models` to list available models. ### Quick Start Example @@ -70,7 +71,7 @@ Here's a practical starting configuration: ```jsonc { - "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json", + "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { // Main orchestrator: Claude Opus or Kimi K2.5 work best @@ -93,19 +94,19 @@ Here's a practical starting configuration: }, "categories": { - // quick — trivial tasks + // quick - trivial tasks "quick": { "model": "opencode/gpt-5-nano" }, - // unspecified-low — moderate tasks + // unspecified-low - moderate tasks "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, - // unspecified-high — complex work + // unspecified-high - complex work "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, - // writing — docs/prose + // writing - docs/prose "writing": { "model": "google/gemini-3-flash" }, - // visual-engineering — Gemini dominates visual tasks + // visual-engineering - Gemini dominates visual tasks "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high", @@ -159,24 +160,24 @@ Disable agents entirely: `{ "disabled_agents": ["oracle", "multimodal-looker"] } #### Agent Options -| Option | Type | Description | -| ----------------- | ------------- | ------------------------------------------------------ | -| `model` | string | Model override (`provider/model`) | -| `fallback_models` | string\|array | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings. | -| `temperature` | number | Sampling temperature | -| `top_p` | number | Top-p sampling | -| `prompt` | string | Replace system prompt | -| `prompt_append` | string | Append to system prompt | +| Option | Type | Description | +| ----------------- | -------------- | --------------------------------------------------------------- | +| `model` | string | Model override (`provider/model`) | +| `fallback_models` | string\|array | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings | +| `temperature` | number | Sampling temperature | +| `top_p` | number | Top-p sampling | +| `prompt` | string | Replace system prompt. Supports `file://` URIs | +| `prompt_append` | string | Append to system prompt. Supports `file://` URIs | | `tools` | array | Allowed tools list | | `disable` | boolean | Disable this agent | | `mode` | string | Agent mode | | `color` | string | UI color | | `permission` | object | Per-tool permissions (see below) | | `category` | string | Inherit model from category | -| `variant` | string | Model variant: `max`, `high`, `medium`, `low`, `xhigh` | +| `variant` | string | Model variant: `max`, `high`, `medium`, `low`, `xhigh`. Normalized to supported values | | `maxTokens` | number | Max response tokens | | `thinking` | object | Anthropic extended thinking | -| `reasoningEffort` | string | OpenAI reasoning: `low`, `medium`, `high`, `xhigh` | +| `reasoningEffort` | string | OpenAI reasoning: `low`, `medium`, `high`, `xhigh`. Normalized to supported values | | `textVerbosity` | string | Text verbosity: `low`, `medium`, `high` | | `providerOptions` | object | Provider-specific options | @@ -216,6 +217,58 @@ Control what tools an agent can use: | `doom_loop` | `ask` / `allow` / `deny` | | `external_directory` | `ask` / `allow` / `deny` | + +#### Fallback Models with Per-Model Settings + +`fallback_models` accepts either a single model string or an array. Array entries can be plain strings or objects with individual model settings: + +```jsonc +{ + "agents": { + "sisyphus": { + "model": "anthropic/claude-opus-4-6", + "fallback_models": [ + // Simple string fallback + "openai/gpt-5.4", + // Object with per-model settings + { + "model": "google/gemini-3.1-pro", + "variant": "high", + "temperature": 0.2 + }, + { + "model": "anthropic/claude-sonnet-4-6", + "thinking": { "type": "enabled", "budgetTokens": 64000 } + } + ] + } + } +} +``` + +Object entries support: `model`, `variant`, `reasoningEffort`, `temperature`, `top_p`, `maxTokens`, `thinking`. + +#### File URIs for Prompts + +Both `prompt` and `prompt_append` support loading content from files via `file://` URIs: + +```jsonc +{ + "agents": { + "sisyphus": { + "prompt_append": "file:///absolute/path/to/prompt.txt" + }, + "oracle": { + "prompt": "file://./relative/to/project/prompt.md" + }, + "explore": { + "prompt_append": "file://~/home/dir/prompt.txt" + } + } +} +``` + +Paths can be absolute (`file:///abs/path`), relative to project root (`file://./rel/path`), or home-relative (`file://~/home/path`). ### Categories Domain-specific model delegation used by the `task()` tool. When Sisyphus delegates work, it picks a category, not a model name. @@ -240,16 +293,16 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega | Option | Type | Default | Description | | ------------------- | ------------- | ------- | ------------------------------------------------------------------- | | `model` | string | - | Model override | -| `fallback_models` | string\|array | - | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings. | +| `fallback_models` | string\|array | - | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings | | `temperature` | number | - | Sampling temperature | | `top_p` | number | - | Top-p sampling | | `maxTokens` | number | - | Max response tokens | | `thinking` | object | - | Anthropic extended thinking | -| `reasoningEffort` | string | - | OpenAI reasoning effort | +| `reasoningEffort` | string | - | OpenAI reasoning effort. Unsupported values are normalized | | `textVerbosity` | string | - | Text verbosity | | `tools` | array | - | Allowed tools | | `prompt_append` | string | - | Append to system prompt | -| `variant` | string | - | Model variant | +| `variant` | string | - | Model variant. Unsupported values are normalized | | `description` | string | - | Shown in `task()` tool prompt | | `is_unstable_agent` | boolean | `false` | Force background mode + monitoring. Auto-enabled for Gemini models. | @@ -259,20 +312,31 @@ Disable categories: `{ "disabled_categories": ["ultrabrain"] }` 3-step priority at runtime: -1. **User override** — model set in config → used exactly as-is -2. **Provider fallback chain** — tries each provider in priority order until available -3. **System default** — falls back to OpenCode's configured default model +1. **User override** - model set in config → used exactly as-is. Even on cold cache (first run without model availability data), explicit user configuration takes precedence over hardcoded fallback chains +2. **Provider fallback chain** - tries each provider in priority order until available +3. **System default** - falls back to OpenCode's configured default model + +#### Model Settings Compatibility + +`variant` and `reasoningEffort` values are automatically normalized to what each model supports. If you specify a variant or reasoning effort level that a model does not support, it is adjusted to the closest supported value rather than causing errors. + +Examples: +- Claude models do not support `reasoningEffort` - it is removed automatically +- GPT-4.1 does not support reasoning - `reasoningEffort` is removed +- o-series models support `none` through `high` - `xhigh` is downgraded to `high` +- GPT-5 supports `none`, `minimal`, `low`, `medium`, `high`, `xhigh` - all pass through + #### Agent Provider Chains | Agent | Default Model | Provider Priority | | --------------------- | ------------------- | ---------------------------------------------------------------------------- | | **Sisyphus** | `claude-opus-4-6` | `claude-opus-4-6` → `glm-5` → `big-pickle` | -| **Hephaestus** | `gpt-5.3-codex` | `gpt-5.3-codex` → `gpt-5.4` (GitHub Copilot fallback) | +| **Hephaestus** | `gpt-5.4` | `gpt-5.4` | | **oracle** | `gpt-5.4` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-6` | -| **librarian** | `gemini-3-flash` | `gemini-3-flash` → `minimax-m2.5-free` → `big-pickle` | -| **explore** | `grok-code-fast-1` | `grok-code-fast-1` → `minimax-m2.5-free` → `claude-haiku-4-5` → `gpt-5-nano` | -| **multimodal-looker** | `gpt-5.3-codex` | `gpt-5.3-codex` → `k2p5` → `gemini-3-flash` → `glm-4.6v` → `gpt-5-nano` | +| **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7` → `opencode/minimax-m2.5` → `claude-haiku-4-5` → `gpt-5-nano` | +| **explore** | `grok-code-fast-1` | `grok-code-fast-1` → `opencode-go/minimax-m2.7` → `opencode/minimax-m2.5` → `claude-haiku-4-5` → `gpt-5-nano` | +| **multimodal-looker** | `gpt-5.4` | `gpt-5.4` → `k2p5` → `glm-4.6v` → `gpt-5-nano` | | **Prometheus** | `claude-opus-4-6` | `claude-opus-4-6` → `gpt-5.4` → `gemini-3.1-pro` | | **Metis** | `claude-opus-4-6` | `claude-opus-4-6` → `gpt-5.4` → `gemini-3.1-pro` | | **Momus** | `gpt-5.4` | `gpt-5.4` → `claude-opus-4-6` → `gemini-3.1-pro` | @@ -286,12 +350,12 @@ Disable categories: `{ "disabled_categories": ["ultrabrain"] }` | **ultrabrain** | `gpt-5.4` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-6` | | **deep** | `gpt-5.3-codex` | `gpt-5.3-codex` → `claude-opus-4-6` → `gemini-3.1-pro` | | **artistry** | `gemini-3.1-pro` | `gemini-3.1-pro` → `claude-opus-4-6` → `gpt-5.4` | -| **quick** | `gpt-5.4-mini` | `gpt-5.4-mini` → `claude-haiku-4-5` → `gemini-3-flash` → `minimax-m2.5` → `gpt-5-nano` | -| **unspecified-low** | `claude-sonnet-4-6` | `claude-sonnet-4-6` → `gpt-5.3-codex` → `gemini-3-flash` | +| **quick** | `gpt-5.4-mini` | `gpt-5.4-mini` → `claude-haiku-4-5` → `gemini-3-flash` → `minimax-m2.7` → `gpt-5-nano` | +| **unspecified-low** | `claude-sonnet-4-6` | `claude-sonnet-4-6` → `gpt-5.3-codex` → `gemini-3-flash` → `minimax-m2.7` | | **unspecified-high** | `claude-opus-4-6` | `claude-opus-4-6` → `gpt-5.4 (high)` → `glm-5` → `k2p5` → `kimi-k2.5` | -| **writing** | `gemini-3-flash` | `gemini-3-flash` → `claude-sonnet-4-6` | +| **writing** | `gemini-3-flash` | `gemini-3-flash` → `claude-sonnet-4-6` → `minimax-m2.7` | -Run `bunx oh-my-openagent doctor --verbose` to see effective model resolution for your config. +Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config. --- @@ -425,9 +489,10 @@ Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `sessio **Notes:** -- `directory-agents-injector` — auto-disabled on OpenCode 1.1.37+ (native AGENTS.md support) -- `no-sisyphus-gpt` — **do not disable**. It blocks incompatible GPT models for Sisyphus while allowing the dedicated GPT-5.4 prompt path. +- `directory-agents-injector` - auto-disabled on OpenCode 1.1.37+ (native AGENTS.md support) +- `no-sisyphus-gpt` - **do not disable**. It blocks incompatible GPT models for Sisyphus while allowing the dedicated GPT-5.4 prompt path. - `startup-toast` is a sub-feature of `auto-update-checker`. Disable just the toast by adding `startup-toast` to `disabled_hooks`. +- `session-recovery` - automatically recovers from recoverable session errors (missing tool results, unavailable tools, thinking block violations). Shows toast notifications during recovery. Enable `experimental.auto_resume` for automatic retry after recovery. ### Commands @@ -504,7 +569,7 @@ Force-enable session notifications: { "notification": { "force_enable": true } } ``` -`force_enable` (`false`) — force session-notification even if external notification plugins are detected. +`force_enable` (`false`) - force session-notification even if external notification plugins are detected. ### MCPs diff --git a/docs/reference/features.md b/docs/reference/features.md index 52f41fe3e..6d1043ce5 100644 --- a/docs/reference/features.md +++ b/docs/reference/features.md @@ -6,15 +6,16 @@ Oh-My-OpenAgent provides 11 specialized AI agents. Each has distinct expertise, ### Core Agents +Core-agent tab cycling is deterministic. The fixed priority order is Sisyphus, Hephaestus, Prometheus, and Atlas. Remaining agents follow after that stable core ordering. + | Agent | Model | Purpose | | --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `glm-5` → `big-pickle`. | -| **Hephaestus** | `gpt-5.3-codex` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Fallback: `gpt-5.4` on GitHub Copilot. Requires a GPT-capable provider. | +| **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `glm-5` → `big-pickle`. | +| **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. | | **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `gemini-3.1-pro` → `claude-opus-4-6`. | -| **Librarian** | `gemini-3-flash` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `minimax-m2.5-free` → `big-pickle`. | -| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `minimax-m2.5-free` → `claude-haiku-4-5` → `gpt-5-nano`. | -| **Multimodal-Looker** | `gpt-5.3-codex` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `k2p5` → `gemini-3-flash` → `glm-4.6v` → `gpt-5-nano`. | - +| **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Primary OpenCode Go path uses MiniMax M2.7. Other provider catalogs may still fall back to MiniMax M2.5, then `claude-haiku-4-5` and `gpt-5-nano`. | +| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Primary path stays on Grok Code Fast 1. MiniMax M2.7 is now used where provider catalogs expose it, while some OpenCode fallback paths still use MiniMax M2.5 for catalog compatibility. | +| **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `k2p5` → `glm-4.6v` → `gpt-5-nano`. | ### Planning Agents | Agent | Model | Purpose | @@ -89,8 +90,9 @@ When running inside tmux: - Watch multiple agents work in real-time - Each pane shows agent output live - Auto-cleanup when agents complete +- **Stable agent ordering**: the core tab cycle stays deterministic with Sisyphus, Hephaestus, Prometheus, and Atlas first -Customize agent models, prompts, and permissions in `oh-my-openagent.json`. +Customize agent models, prompts, and permissions in `oh-my-opencode.jsonc`. ## Category System @@ -129,7 +131,7 @@ task({ ### Custom Categories -You can define custom categories in `oh-my-openagent.json`. +You can define custom categories in your plugin config file. During the rename transition, both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` basenames are recognized. #### Category Configuration Schema @@ -188,6 +190,60 @@ When you use a Category, a special agent called **Sisyphus-Junior** performs the - **Characteristic**: Cannot **re-delegate** tasks to other agents. - **Purpose**: Prevents infinite delegation loops and ensures focus on the assigned task. +## Advanced Configuration + +### Fallback Models + +Configure per-agent fallback chains with arrays that can mix plain model strings and per-model objects: + +```jsonc +{ + "agents": { + "sisyphus": { + "fallback_models": [ + "opencode/glm-5", + { "model": "openai/gpt-5.4", "variant": "high" }, + { "model": "anthropic/claude-sonnet-4-6", "thinking": { "type": "enabled", "budgetTokens": 64000 } } + ] + } + } +} +``` + +When a model errors, the runtime can move through the configured fallback array. Object entries let you tune the backup model itself instead of only swapping the model name. + +### File-Based Prompts + +Load agent system prompts from external files using `file://` URLs: + +```jsonc +{ + "agents": { + "sisyphus": { + "prompt": "file:///path/to/custom-prompt.md" + } + } +} +``` + +Useful for: +- Version controlling prompts separately from config +- Sharing prompts across projects +- Keeping configuration files concise + +The file content is loaded at runtime and injected as the agent's system prompt. + +### Session Recovery + +The system automatically recovers from common session failures without user intervention: + +- **Missing tool results**: reconstructs recoverable tool state and skips invalid tool-part IDs instead of failing the whole recovery pass +- **Thinking block violations**: Recovers from API thinking block mismatches +- **Empty messages**: Reconstructs message history when content is missing +- **Context window limits**: Gracefully handles Claude context window exceeded errors with intelligent compaction +- **JSON parse errors**: Recovers from malformed tool outputs + +Recovery happens transparently during agent execution. You see the result, not the failure. ## Skills Skills provide specialized workflows with embedded MCP servers and detailed instructions. A Skill is a mechanism that injects **specialized knowledge (Context)** and **tools (MCP)** for specific domains into agents. @@ -844,7 +900,7 @@ When a skill MCP has `oauth` configured: Pre-authenticate via CLI: ```bash -bunx oh-my-openagent mcp oauth login --server-url https://api.example.com +bunx oh-my-opencode mcp oauth login --server-url https://api.example.com ``` ## Context Injection diff --git a/package.json b/package.json index 952fdbcfc..2c4a4e857 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,12 @@ "build:all": "bun run build && bun run build:binaries", "build:binaries": "bun run script/build-binaries.ts", "build:schema": "bun run script/build-schema.ts", + "build:model-capabilities": "bun run script/build-model-capabilities.ts", "clean": "rm -rf dist", "prepare": "bun run build", "postinstall": "node postinstall.mjs", "prepublishOnly": "bun run clean && bun run build", + "test:model-capabilities": "bun test src/shared/model-capability-aliases.test.ts src/shared/model-capability-guardrails.test.ts src/shared/model-capabilities.test.ts src/cli/doctor/checks/model-resolution.test.ts --bail", "typecheck": "tsc --noEmit", "test": "bun test" }, diff --git a/script/build-model-capabilities.ts b/script/build-model-capabilities.ts new file mode 100644 index 000000000..64f1d84f2 --- /dev/null +++ b/script/build-model-capabilities.ts @@ -0,0 +1,13 @@ +import { writeFileSync } from "fs" +import { resolve } from "path" +import { + fetchModelCapabilitiesSnapshot, + MODELS_DEV_SOURCE_URL, +} from "../src/shared/model-capabilities-cache" + +const OUTPUT_PATH = resolve(import.meta.dir, "../src/generated/model-capabilities.generated.json") + +console.log(`Fetching model capabilities snapshot from ${MODELS_DEV_SOURCE_URL}...`) +const snapshot = await fetchModelCapabilitiesSnapshot() +writeFileSync(OUTPUT_PATH, `${JSON.stringify(snapshot, null, 2)}\n`) +console.log(`Generated ${OUTPUT_PATH} with ${Object.keys(snapshot.models).length} models`) diff --git a/signatures/cla.json b/signatures/cla.json index 46ed01db9..e438f7f49 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2303,6 +2303,38 @@ "created_at": "2026-03-23T04:28:20Z", "repoId": 1108837393, "pullRequestNo": 2758 + }, + { + "name": "anas-asghar4831", + "id": 110368394, + "comment_id": 4128950310, + "created_at": "2026-03-25T18:48:19Z", + "repoId": 1108837393, + "pullRequestNo": 2837 + }, + { + "name": "clansty", + "id": 18461360, + "comment_id": 4129934858, + "created_at": "2026-03-25T21:33:35Z", + "repoId": 1108837393, + "pullRequestNo": 2839 + }, + { + "name": "ventsislav-georgiev", + "id": 5616486, + "comment_id": 4130417794, + "created_at": "2026-03-25T23:11:32Z", + "repoId": 1108837393, + "pullRequestNo": 2840 + }, + { + "name": "kuitos", + "id": 5206843, + "comment_id": 4133207953, + "created_at": "2026-03-26T09:55:49Z", + "repoId": 1108837393, + "pullRequestNo": 2833 } ] } \ No newline at end of file diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index a4dcf175a..bc7873233 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -11,10 +11,10 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each | Agent | Model | Temp | Mode | Fallback Chain | Purpose | |-------|-------|------|------|----------------|---------| | **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 → kimi-k2.5 → gpt-5.4 medium → glm-5 → big-pickle | Main orchestrator, plans + delegates | -| **Hephaestus** | gpt-5.3-codex medium | 0.1 | all | gpt-5.4 medium (copilot) | Autonomous deep worker | +| **Hephaestus** | gpt-5.4 medium | 0.1 | all | — | Autonomous deep worker | | **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high → claude-opus-4-6 max | Read-only consultation | -| **Librarian** | gemini-3-flash | 0.1 | subagent | minimax-m2.5-free → big-pickle | External docs/code search | -| **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.5-free → claude-haiku-4-5 → gpt-5-nano | Contextual grep | +| **Librarian** | minimax-m2.7 | 0.1 | subagent | minimax-m2.7-highspeed → claude-haiku-4-5 → gpt-5-nano | External docs/code search | +| **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.7-highspeed → minimax-m2.7 → claude-haiku-4-5 → gpt-5-nano | Contextual grep | | **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 → gemini-3-flash → glm-4.6v → gpt-5-nano | PDF/image analysis | | **Metis** | claude-opus-4-6 max | **0.3** | subagent | gpt-5.4 high → gemini-3.1-pro high | Pre-planning consultant | | **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-6 max → gemini-3.1-pro high | Plan reviewer | diff --git a/src/agents/builtin-agents/general-agents.ts b/src/agents/builtin-agents/general-agents.ts index f5fd1d920..7d9d52979 100644 --- a/src/agents/builtin-agents/general-agents.ts +++ b/src/agents/builtin-agents/general-agents.ts @@ -78,12 +78,16 @@ export function collectPendingBuiltinAgents(input: { }) if (!resolution) { if (override?.model) { - log("[agent-registration] User-configured model could not be resolved, falling back", { + // User explicitly configured a model but resolution failed (e.g., cold cache). + // Honor the user's choice directly instead of falling back to hardcoded chain. + log("[agent-registration] User-configured model not resolved, using as-is", { agent: agentName, configuredModel: override.model, }) + resolution = { model: override.model, provenance: "override" as const } + } else { + resolution = getFirstFallbackModel(requirement) } - resolution = getFirstFallbackModel(requirement) } if (!resolution) continue const { model, variant: resolvedVariant } = resolution diff --git a/src/agents/types.test.ts b/src/agents/types.test.ts index 5d712fc94..c911324fd 100644 --- a/src/agents/types.test.ts +++ b/src/agents/types.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from "bun:test"; -import { isGptModel, isGeminiModel, isGpt5_4Model } from "./types"; +import { isGptModel, isGeminiModel, isGpt5_4Model, isMiniMaxModel } from "./types"; describe("isGpt5_4Model", () => { test("detects gpt-5.4 models", () => { @@ -79,6 +79,28 @@ describe("isGptModel", () => { }); }); +describe("isMiniMaxModel", () => { + test("detects minimax models with provider prefix", () => { + expect(isMiniMaxModel("opencode-go/minimax-m2.7")).toBe(true); + expect(isMiniMaxModel("opencode/minimax-m2.7-highspeed")).toBe(true); + expect(isMiniMaxModel("opencode-go/minimax-m2.5")).toBe(true); + expect(isMiniMaxModel("opencode/minimax-m2.5-free")).toBe(true); + }); + + test("detects minimax models without provider prefix", () => { + expect(isMiniMaxModel("minimax-m2.7")).toBe(true); + expect(isMiniMaxModel("minimax-m2.7-highspeed")).toBe(true); + expect(isMiniMaxModel("minimax-m2.5")).toBe(true); + }); + + test("does not match non-minimax models", () => { + expect(isMiniMaxModel("openai/gpt-5.4")).toBe(false); + expect(isMiniMaxModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false); + expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false); + }); +}); + describe("isGeminiModel", () => { test("#given google provider models #then returns true", () => { expect(isGeminiModel("google/gemini-3.1-pro")).toBe(true); diff --git a/src/agents/types.ts b/src/agents/types.ts index 1d975c182..5f5fa6bfe 100644 --- a/src/agents/types.ts +++ b/src/agents/types.ts @@ -91,6 +91,11 @@ export function isGpt5_3CodexModel(model: string): boolean { const GEMINI_PROVIDERS = ["google/", "google-vertex/"]; +export function isMiniMaxModel(model: string): boolean { + const modelName = extractModelName(model).toLowerCase(); + return modelName.includes("minimax"); +} + export function isGeminiModel(model: string): boolean { if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix))) return true; diff --git a/src/agents/utils.test.ts b/src/agents/utils.test.ts index b0280f52e..c3251b297 100644 --- a/src/agents/utils.test.ts +++ b/src/agents/utils.test.ts @@ -642,7 +642,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => // #then expect(agents.hephaestus).toBeDefined() - expect(agents.hephaestus.model).toBe("openai/gpt-5.3-codex") + expect(agents.hephaestus.model).toBe("openai/gpt-5.4") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index 29eef9db0..1db43d5de 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -202,7 +202,7 @@ exports[`generateModelConfig single native provider uses OpenAI models when only "variant": "medium", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { @@ -287,7 +287,7 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa "variant": "medium", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { @@ -490,7 +490,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "metis": { @@ -565,7 +565,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "metis": { @@ -641,7 +641,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/claude-haiku-4-5", }, "hephaestus": { - "model": "opencode/gpt-5.3-codex", + "model": "opencode/gpt-5.4", "variant": "medium", }, "metis": { @@ -716,7 +716,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/claude-haiku-4-5", }, "hephaestus": { - "model": "opencode/gpt-5.3-codex", + "model": "opencode/gpt-5.4", "variant": "medium", }, "metis": { @@ -1049,7 +1049,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { - "model": "opencode/gpt-5.3-codex", + "model": "opencode/gpt-5.4", "variant": "medium", }, "metis": { @@ -1124,7 +1124,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "github-copilot/gpt-5-mini", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "metis": { @@ -1329,7 +1329,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/claude-haiku-4-5", }, "hephaestus": { - "model": "opencode/gpt-5.3-codex", + "model": "github-copilot/gpt-5.4", "variant": "medium", }, "librarian": { @@ -1407,7 +1407,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { @@ -1485,7 +1485,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "anthropic/claude-haiku-4-5", }, "hephaestus": { - "model": "openai/gpt-5.3-codex", + "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { diff --git a/src/cli/cli-installer.ts b/src/cli/cli-installer.ts index b97141bca..9f51eedfb 100644 --- a/src/cli/cli-installer.ts +++ b/src/cli/cli-installer.ts @@ -1,4 +1,5 @@ import color from "picocolors" +import { PLUGIN_NAME } from "../shared" import type { InstallArgs } from "./types" import { addPluginToOpenCodeConfig, @@ -32,7 +33,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi } console.log() printInfo( - "Usage: bunx oh-my-opencode install --no-tui --claude= --gemini= --copilot=", + `Usage: bunx ${PLUGIN_NAME} install --no-tui --claude= --gemini= --copilot=`, ) console.log() return 1 @@ -65,7 +66,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi const config = argsToConfig(args) - printStep(step++, totalSteps, "Adding oh-my-opencode plugin...") + printStep(step++, totalSteps, `Adding ${PLUGIN_NAME} plugin...`) const pluginResult = await addPluginToOpenCodeConfig(version) if (!pluginResult.success) { printError(`Failed: ${pluginResult.error}`) @@ -75,7 +76,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi `Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`, ) - printStep(step++, totalSteps, "Writing oh-my-opencode configuration...") + printStep(step++, totalSteps, `Writing ${PLUGIN_NAME} configuration...`) const omoResult = writeOmoConfig(config) if (!omoResult.success) { printError(`Failed: ${omoResult.error}`) diff --git a/src/cli/cli-program.ts b/src/cli/cli-program.ts index ddab0483c..15d3d0489 100644 --- a/src/cli/cli-program.ts +++ b/src/cli/cli-program.ts @@ -3,6 +3,7 @@ import { install } from "./install" import { run } from "./run" import { getLocalVersion } from "./get-local-version" import { doctor } from "./doctor" +import { refreshModelCapabilities } from "./refresh-model-capabilities" import { createMcpOAuthCommand } from "./mcp-oauth" import type { InstallArgs } from "./types" import type { RunOptions } from "./run" @@ -176,6 +177,21 @@ Examples: process.exit(exitCode) }) +program + .command("refresh-model-capabilities") + .description("Refresh the cached models.dev-based model capabilities snapshot") + .option("-d, --directory ", "Working directory to read oh-my-opencode config from") + .option("--source-url ", "Override the models.dev source URL") + .option("--json", "Output refresh summary as JSON") + .action(async (options) => { + const exitCode = await refreshModelCapabilities({ + directory: options.directory, + sourceUrl: options.sourceUrl, + json: options.json ?? false, + }) + process.exit(exitCode) + }) + program .command("version") .description("Show version information") diff --git a/src/cli/config-manager.test.ts b/src/cli/config-manager.test.ts deleted file mode 100644 index 536695a76..000000000 --- a/src/cli/config-manager.test.ts +++ /dev/null @@ -1,300 +0,0 @@ -import { describe, expect, test, mock, afterEach } from "bun:test" - -import { getPluginNameWithVersion, fetchNpmDistTags, generateOmoConfig } from "./config-manager" -import type { InstallConfig } from "./types" - -describe("getPluginNameWithVersion", () => { - const originalFetch = globalThis.fetch - - afterEach(() => { - globalThis.fetch = originalFetch - }) - - test("returns @latest when current version matches latest tag", async () => { - // #given npm dist-tags with latest=2.14.0 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }), - } as Response) - ) as unknown as typeof fetch - - // #when current version is 2.14.0 - const result = await getPluginNameWithVersion("2.14.0") - - // #then should use @latest tag - expect(result).toBe("oh-my-opencode@latest") - }) - - test("returns @beta when current version matches beta tag", async () => { - // #given npm dist-tags with beta=3.0.0-beta.3 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }), - } as Response) - ) as unknown as typeof fetch - - // #when current version is 3.0.0-beta.3 - const result = await getPluginNameWithVersion("3.0.0-beta.3") - - // #then should use @beta tag - expect(result).toBe("oh-my-opencode@beta") - }) - - test("returns @next when current version matches next tag", async () => { - // #given npm dist-tags with next=3.1.0-next.1 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3", next: "3.1.0-next.1" }), - } as Response) - ) as unknown as typeof fetch - - // #when current version is 3.1.0-next.1 - const result = await getPluginNameWithVersion("3.1.0-next.1") - - // #then should use @next tag - expect(result).toBe("oh-my-opencode@next") - }) - - test("returns prerelease channel tag when no dist-tag matches prerelease version", async () => { - // #given npm dist-tags with beta=3.0.0-beta.3 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }), - } as Response) - ) as unknown as typeof fetch - - // #when current version is old beta 3.0.0-beta.2 - const result = await getPluginNameWithVersion("3.0.0-beta.2") - - // #then should preserve prerelease channel - expect(result).toBe("oh-my-opencode@beta") - }) - - test("returns prerelease channel tag when fetch fails", async () => { - // #given network failure - globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch - - // #when current version is 3.0.0-beta.3 - const result = await getPluginNameWithVersion("3.0.0-beta.3") - - // #then should preserve prerelease channel - expect(result).toBe("oh-my-opencode@beta") - }) - - test("returns bare package name when npm returns non-ok response for stable version", async () => { - // #given npm returns 404 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: false, - status: 404, - } as Response) - ) as unknown as typeof fetch - - // #when current version is 2.14.0 - const result = await getPluginNameWithVersion("2.14.0") - - // #then should fall back to bare package entry - expect(result).toBe("oh-my-opencode") - }) - - test("prioritizes latest over other tags when version matches multiple", async () => { - // #given version matches both latest and beta (during release promotion) - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ beta: "3.0.0", latest: "3.0.0", next: "3.1.0-alpha.1" }), - } as Response) - ) as unknown as typeof fetch - - // #when current version matches both - const result = await getPluginNameWithVersion("3.0.0") - - // #then should prioritize @latest - expect(result).toBe("oh-my-opencode@latest") - }) -}) - -describe("fetchNpmDistTags", () => { - const originalFetch = globalThis.fetch - - afterEach(() => { - globalThis.fetch = originalFetch - }) - - test("returns dist-tags on success", async () => { - // #given npm returns dist-tags - globalThis.fetch = mock(() => - Promise.resolve({ - ok: true, - json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }), - } as Response) - ) as unknown as typeof fetch - - // #when fetching dist-tags - const result = await fetchNpmDistTags("oh-my-opencode") - - // #then should return the tags - expect(result).toEqual({ latest: "2.14.0", beta: "3.0.0-beta.3" }) - }) - - test("returns null on network failure", async () => { - // #given network failure - globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch - - // #when fetching dist-tags - const result = await fetchNpmDistTags("oh-my-opencode") - - // #then should return null - expect(result).toBeNull() - }) - - test("returns null on non-ok response", async () => { - // #given npm returns 404 - globalThis.fetch = mock(() => - Promise.resolve({ - ok: false, - status: 404, - } as Response) - ) as unknown as typeof fetch - - // #when fetching dist-tags - const result = await fetchNpmDistTags("oh-my-opencode") - - // #then should return null - expect(result).toBeNull() - }) -}) - -describe("generateOmoConfig - model fallback system", () => { - test("uses github-copilot sonnet fallback when only copilot available", () => { - // #given user has only copilot (no max plan) - const config: InstallConfig = { - hasClaude: false, - isMax20: false, - hasOpenAI: false, - hasGemini: false, - hasCopilot: true, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then Sisyphus uses Copilot (OR logic - copilot is in claude-opus-4-6 providers) - expect((result.agents as Record).sisyphus.model).toBe("github-copilot/claude-opus-4.6") - }) - - test("uses ultimate fallback when no providers configured", () => { - // #given user has no providers - const config: InstallConfig = { - hasClaude: false, - isMax20: false, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then Sisyphus is omitted (requires all fallback providers) - expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json") - expect((result.agents as Record).sisyphus).toBeUndefined() - }) - - test("uses ZAI model for librarian when Z.ai is available", () => { - // #given user has Z.ai and Claude max20 - const config: InstallConfig = { - hasClaude: true, - isMax20: true, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: true, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then librarian should use ZAI model - expect((result.agents as Record).librarian.model).toBe("zai-coding-plan/glm-4.7") - // #then Sisyphus uses Claude (OR logic) - expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-6") - }) - - test("uses native OpenAI models when only ChatGPT available", () => { - // #given user has only ChatGPT subscription - const config: InstallConfig = { - hasClaude: false, - isMax20: false, - hasOpenAI: true, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then Sisyphus resolves to gpt-5.4 medium (openai is now in sisyphus chain) - expect((result.agents as Record).sisyphus.model).toBe("openai/gpt-5.4") - expect((result.agents as Record).sisyphus.variant).toBe("medium") - // #then Oracle should use native OpenAI (first fallback entry) - expect((result.agents as Record).oracle.model).toBe("openai/gpt-5.4") - // #then multimodal-looker should use native OpenAI (first fallback entry is gpt-5.4) - expect((result.agents as Record)["multimodal-looker"].model).toBe("openai/gpt-5.4") - }) - - test("uses haiku for explore when Claude max20", () => { - // #given user has Claude max20 - const config: InstallConfig = { - hasClaude: true, - isMax20: true, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then explore should use haiku (max20 plan uses Claude quota) - expect((result.agents as Record).explore.model).toBe("anthropic/claude-haiku-4-5") - }) - - test("uses haiku for explore regardless of max20 flag", () => { - // #given user has Claude but not max20 - const config: InstallConfig = { - hasClaude: true, - isMax20: false, - hasOpenAI: false, - hasGemini: false, - hasCopilot: false, - hasOpencodeZen: false, - hasZaiCodingPlan: false, - hasKimiForCoding: false, - } - - // #when generating config - const result = generateOmoConfig(config) - - // #then explore should use haiku (isMax20 doesn't affect explore anymore) - expect((result.agents as Record).explore.model).toBe("anthropic/claude-haiku-4-5") - }) -}) diff --git a/src/cli/config-manager/add-plugin-to-opencode-config.ts b/src/cli/config-manager/add-plugin-to-opencode-config.ts index 90a78f0ae..19b265ec5 100644 --- a/src/cli/config-manager/add-plugin-to-opencode-config.ts +++ b/src/cli/config-manager/add-plugin-to-opencode-config.ts @@ -41,37 +41,39 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise const config = parseResult.config const plugins = config.plugin ?? [] - // Check for existing plugin (either current or legacy name) - const currentNameIndex = plugins.findIndex( + const canonicalEntries = plugins.filter( (plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) ) - const legacyNameIndex = plugins.findIndex( + const legacyEntries = plugins.filter( (plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`) ) + const otherPlugins = plugins.filter( + (plugin) => !(plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`)) + && !(plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)) + ) - // If either name exists, update to new name - if (currentNameIndex !== -1) { - if (plugins[currentNameIndex] === pluginEntry) { - return { success: true, configPath: path } - } - plugins[currentNameIndex] = pluginEntry - } else if (legacyNameIndex !== -1) { - // Upgrade legacy name to new name - plugins[legacyNameIndex] = pluginEntry + const normalizedPlugins = [...otherPlugins] + + if (canonicalEntries.length > 0) { + normalizedPlugins.push(canonicalEntries[0]) + } else if (legacyEntries.length > 0) { + const versionMatch = legacyEntries[0].match(/@(.+)$/) + const preservedVersion = versionMatch ? versionMatch[1] : null + normalizedPlugins.push(preservedVersion ? `${PLUGIN_NAME}@${preservedVersion}` : pluginEntry) } else { - plugins.push(pluginEntry) + normalizedPlugins.push(pluginEntry) } - config.plugin = plugins + config.plugin = normalizedPlugins if (format === "jsonc") { const content = readFileSync(path, "utf-8") - const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/ + const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/ const match = content.match(pluginArrayRegex) if (match) { - const formattedPlugins = plugins.map((p) => `"${p}"`).join(",\n ") - const newContent = content.replace(pluginArrayRegex, `"plugin": [\n ${formattedPlugins}\n ]`) + const formattedPlugins = normalizedPlugins.map((p) => `"${p}"`).join(",\n ") + const newContent = content.replace(pluginArrayRegex, `$1[\n ${formattedPlugins}\n ]`) writeFileSync(path, newContent) } else { const newContent = content.replace(/(\{)/, `$1\n "plugin": ["${pluginEntry}"],`) diff --git a/src/cli/config-manager/generate-omo-config.test.ts b/src/cli/config-manager/generate-omo-config.test.ts new file mode 100644 index 000000000..2a1a24e5b --- /dev/null +++ b/src/cli/config-manager/generate-omo-config.test.ts @@ -0,0 +1,142 @@ +/// + +import { describe, expect, test } from "bun:test" + +import { generateOmoConfig } from "../config-manager" +import type { InstallConfig } from "../types" + +describe("generateOmoConfig - model fallback system", () => { + test("uses github-copilot sonnet fallback when only copilot available", () => { + //#given + const config: InstallConfig = { + hasClaude: false, + isMax20: false, + hasOpenAI: false, + hasGemini: false, + hasCopilot: true, + hasOpencodeZen: false, + hasZaiCodingPlan: false, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect([ + "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4-6", + ]).toContain((result.agents as Record).sisyphus.model) + }) + + test("uses ultimate fallback when no providers configured", () => { + //#given + const config: InstallConfig = { + hasClaude: false, + isMax20: false, + hasOpenAI: false, + hasGemini: false, + hasCopilot: false, + hasOpencodeZen: false, + hasZaiCodingPlan: false, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json") + expect((result.agents as Record).sisyphus).toBeUndefined() + }) + + test("uses ZAI model for librarian when Z.ai is available", () => { + //#given + const config: InstallConfig = { + hasClaude: true, + isMax20: true, + hasOpenAI: false, + hasGemini: false, + hasCopilot: false, + hasOpencodeZen: false, + hasZaiCodingPlan: true, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect((result.agents as Record).librarian.model).toBe("zai-coding-plan/glm-4.7") + expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-6") + }) + + test("uses native OpenAI models when only ChatGPT available", () => { + //#given + const config: InstallConfig = { + hasClaude: false, + isMax20: false, + hasOpenAI: true, + hasGemini: false, + hasCopilot: false, + hasOpencodeZen: false, + hasZaiCodingPlan: false, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect((result.agents as Record).sisyphus.model).toBe("openai/gpt-5.4") + expect((result.agents as Record).sisyphus.variant).toBe("medium") + expect((result.agents as Record).oracle.model).toBe("openai/gpt-5.4") + expect((result.agents as Record)['multimodal-looker'].model).toBe("openai/gpt-5.4") + }) + + test("uses haiku for explore when Claude max20", () => { + //#given + const config: InstallConfig = { + hasClaude: true, + isMax20: true, + hasOpenAI: false, + hasGemini: false, + hasCopilot: false, + hasOpencodeZen: false, + hasZaiCodingPlan: false, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect((result.agents as Record).explore.model).toBe("anthropic/claude-haiku-4-5") + }) + + test("uses haiku for explore regardless of max20 flag", () => { + //#given + const config: InstallConfig = { + hasClaude: true, + isMax20: false, + hasOpenAI: false, + hasGemini: false, + hasCopilot: false, + hasOpencodeZen: false, + hasZaiCodingPlan: false, + hasKimiForCoding: false, + hasOpencodeGo: false, + } + + //#when + const result = generateOmoConfig(config) + + //#then + expect((result.agents as Record).explore.model).toBe("anthropic/claude-haiku-4-5") + }) +}) diff --git a/src/cli/config-manager/npm-dist-tags.test.ts b/src/cli/config-manager/npm-dist-tags.test.ts new file mode 100644 index 000000000..3de417290 --- /dev/null +++ b/src/cli/config-manager/npm-dist-tags.test.ts @@ -0,0 +1,56 @@ +/// + +import { afterEach, describe, expect, mock, test } from "bun:test" + +import { fetchNpmDistTags } from "../config-manager" + +describe("fetchNpmDistTags", () => { + const originalFetch = globalThis.fetch + + afterEach(() => { + globalThis.fetch = originalFetch + }) + + test("returns dist-tags on success", async () => { + //#given + globalThis.fetch = mock(() => + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }), + } as Response) + ) as unknown as typeof fetch + + //#when + const result = await fetchNpmDistTags("oh-my-openagent") + + //#then + expect(result).toEqual({ latest: "3.13.1", beta: "3.14.0-beta.1" }) + }) + + test("returns null on network failure", async () => { + //#given + globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch + + //#when + const result = await fetchNpmDistTags("oh-my-openagent") + + //#then + expect(result).toBeNull() + }) + + test("returns null on non-ok response", async () => { + //#given + globalThis.fetch = mock(() => + Promise.resolve({ + ok: false, + status: 404, + } as Response) + ) as unknown as typeof fetch + + //#when + const result = await fetchNpmDistTags("oh-my-openagent") + + //#then + expect(result).toBeNull() + }) +}) diff --git a/src/cli/config-manager/plugin-detection.test.ts b/src/cli/config-manager/plugin-detection.test.ts index 2d4d69945..e03e63357 100644 --- a/src/cli/config-manager/plugin-detection.test.ts +++ b/src/cli/config-manager/plugin-detection.test.ts @@ -28,10 +28,9 @@ describe("detectCurrentConfig - single package detection", () => { delete process.env.OPENCODE_CONFIG_DIR }) - it("detects oh-my-opencode in plugin array", () => { + it("detects both legacy and canonical plugin entries", () => { // given - const config = { plugin: ["oh-my-opencode"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode", "oh-my-openagent@3.11.0"] }, null, 2) + "\n", "utf-8") // when const result = detectCurrentConfig() @@ -40,58 +39,9 @@ describe("detectCurrentConfig - single package detection", () => { expect(result.isInstalled).toBe(true) }) - it("detects oh-my-opencode with version pin", () => { + it("returns false when plugin not present with similar name", () => { // given - const config = { plugin: ["oh-my-opencode@3.11.0"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") - - // when - const result = detectCurrentConfig() - - // then - expect(result.isInstalled).toBe(true) - }) - - it("detects oh-my-openagent as installed (legacy name)", () => { - // given - const config = { plugin: ["oh-my-openagent"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") - - // when - const result = detectCurrentConfig() - - // then - expect(result.isInstalled).toBe(true) - }) - - it("detects oh-my-openagent with version pin as installed (legacy name)", () => { - // given - const config = { plugin: ["oh-my-openagent@3.11.0"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") - - // when - const result = detectCurrentConfig() - - // then - expect(result.isInstalled).toBe(true) - }) - - it("returns false when plugin not present", () => { - // given - const config = { plugin: ["some-other-plugin"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") - - // when - const result = detectCurrentConfig() - - // then - expect(result.isInstalled).toBe(false) - }) - - it("returns false when plugin not present (even with similar name)", () => { - // given - not exactly oh-my-openagent - const config = { plugin: ["oh-my-openagent-extra"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent-extra"] }, null, 2) + "\n", "utf-8") // when const result = detectCurrentConfig() @@ -103,11 +53,7 @@ describe("detectCurrentConfig - single package detection", () => { it("detects OpenCode Go from the existing omo config", () => { // given writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8") - writeFileSync( - testOmoConfigPath, - JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n", - "utf-8", - ) + writeFileSync(testOmoConfigPath, JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n", "utf-8") // when const result = detectCurrentConfig() @@ -137,10 +83,9 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { delete process.env.OPENCODE_CONFIG_DIR }) - it("keeps oh-my-opencode when it already exists", async () => { + it("writes canonical plugin entry for new installs", async () => { // given - const config = { plugin: ["oh-my-opencode"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({}, null, 2) + "\n", "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") @@ -148,13 +93,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { // then expect(result.success).toBe(true) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - expect(savedConfig.plugin).toContain("oh-my-opencode") + expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) }) - it("replaces version-pinned oh-my-opencode@X.Y.Z", async () => { + it("upgrades a bare legacy plugin entry to canonical", async () => { // given - const config = { plugin: ["oh-my-opencode@3.10.0"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") @@ -162,14 +106,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { // then expect(result.success).toBe(true) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - expect(savedConfig.plugin).toContain("oh-my-opencode") - expect(savedConfig.plugin).not.toContain("oh-my-opencode@3.10.0") + expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) }) - it("recognizes oh-my-openagent as already installed (legacy name)", async () => { + it("upgrades a version-pinned legacy entry to canonical", async () => { // given - const config = { plugin: ["oh-my-openagent"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode@3.10.0"] }, null, 2) + "\n", "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") @@ -177,15 +119,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { // then expect(result.success).toBe(true) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - // Should upgrade to new name - expect(savedConfig.plugin).toContain("oh-my-opencode") - expect(savedConfig.plugin).not.toContain("oh-my-openagent") + expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"]) }) - it("replaces version-pinned oh-my-openagent@X.Y.Z with new name", async () => { + it("removes stale legacy entry when canonical and legacy entries both exist", async () => { // given - const config = { plugin: ["oh-my-openagent@3.10.0"] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent", "oh-my-opencode"] }, null, 2) + "\n", "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") @@ -193,15 +132,12 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { // then expect(result.success).toBe(true) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - // Legacy should be replaced with new name - expect(savedConfig.plugin).toContain("oh-my-opencode") - expect(savedConfig.plugin).not.toContain("oh-my-openagent") + expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) }) - it("adds new plugin when none exists", async () => { + it("preserves a canonical entry when it already exists", async () => { // given - const config = {} - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent@3.10.0"] }, null, 2) + "\n", "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") @@ -209,20 +145,21 @@ describe("addPluginToOpenCodeConfig - single package writes", () => { // then expect(result.success).toBe(true) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - expect(savedConfig.plugin).toContain("oh-my-opencode") + expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"]) }) - it("adds plugin when plugin array is empty", async () => { + it("rewrites quoted jsonc plugin field in place", async () => { // given - const config = { plugin: [] } - writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8") + testConfigPath = join(testConfigDir, "opencode.jsonc") + writeFileSync(testConfigPath, '{\n "plugin": ["oh-my-opencode"]\n}\n', "utf-8") // when const result = await addPluginToOpenCodeConfig("3.11.0") // then expect(result.success).toBe(true) - const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) - expect(savedConfig.plugin).toContain("oh-my-opencode") + const savedContent = readFileSync(testConfigPath, "utf-8") + expect(savedContent.includes('"plugin": [\n "oh-my-openagent"\n ]')).toBe(true) + expect(savedContent.includes("oh-my-opencode")).toBe(false) }) }) diff --git a/src/cli/config-manager/plugin-name-with-version.test.ts b/src/cli/config-manager/plugin-name-with-version.test.ts new file mode 100644 index 000000000..7da003338 --- /dev/null +++ b/src/cli/config-manager/plugin-name-with-version.test.ts @@ -0,0 +1,56 @@ +/// + +import { afterEach, describe, expect, mock, test } from "bun:test" + +import { getPluginNameWithVersion } from "../config-manager" + +describe("getPluginNameWithVersion", () => { + const originalFetch = globalThis.fetch + + afterEach(() => { + globalThis.fetch = originalFetch + }) + + test("returns the canonical latest tag when current version matches latest", async () => { + //#given + globalThis.fetch = mock(() => + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }), + } as Response) + ) as unknown as typeof fetch + + //#when + const result = await getPluginNameWithVersion("3.13.1") + + //#then + expect(result).toBe("oh-my-openagent@latest") + }) + + test("preserves the canonical prerelease channel when fetch fails", async () => { + //#given + globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch + + //#when + const result = await getPluginNameWithVersion("3.14.0-beta.1") + + //#then + expect(result).toBe("oh-my-openagent@beta") + }) + + test("returns the canonical bare package name for stable fallback", async () => { + //#given + globalThis.fetch = mock(() => + Promise.resolve({ + ok: false, + status: 404, + } as Response) + ) as unknown as typeof fetch + + //#when + const result = await getPluginNameWithVersion("3.13.1") + + //#then + expect(result).toBe("oh-my-openagent") + }) +}) diff --git a/src/cli/config-manager/plugin-name-with-version.ts b/src/cli/config-manager/plugin-name-with-version.ts index 4dfa7cf6b..a5b034278 100644 --- a/src/cli/config-manager/plugin-name-with-version.ts +++ b/src/cli/config-manager/plugin-name-with-version.ts @@ -1,6 +1,7 @@ +import { PLUGIN_NAME } from "../../shared" import { fetchNpmDistTags } from "./npm-dist-tags" -const DEFAULT_PACKAGE_NAME = "oh-my-opencode" +const DEFAULT_PACKAGE_NAME = PLUGIN_NAME const PRIORITIZED_TAGS = ["latest", "beta", "next"] as const function getFallbackEntry(version: string, packageName: string): string { diff --git a/src/cli/doctor/checks/model-resolution-details.ts b/src/cli/doctor/checks/model-resolution-details.ts index e96655476..3443e92b1 100644 --- a/src/cli/doctor/checks/model-resolution-details.ts +++ b/src/cli/doctor/checks/model-resolution-details.ts @@ -4,6 +4,10 @@ import { getOpenCodeCacheDir } from "../../../shared" import type { AvailableModelsInfo, ModelResolutionInfo, OmoConfig } from "./model-resolution-types" import { formatModelWithVariant, getCategoryEffectiveVariant, getEffectiveVariant } from "./model-resolution-variant" +function formatCapabilityResolutionLabel(mode: string | undefined): string { + return mode ?? "unknown" +} + export function buildModelResolutionDetails(options: { info: ModelResolutionInfo available: AvailableModelsInfo @@ -37,7 +41,7 @@ export function buildModelResolutionDetails(options: { agent.effectiveModel, getEffectiveVariant(agent.name, agent.requirement, options.config) ) - details.push(` ${marker} ${agent.name}: ${display}`) + details.push(` ${marker} ${agent.name}: ${display} [capabilities: ${formatCapabilityResolutionLabel(agent.capabilityDiagnostics?.resolutionMode)}]`) } details.push("") details.push("Categories:") @@ -47,7 +51,7 @@ export function buildModelResolutionDetails(options: { category.effectiveModel, getCategoryEffectiveVariant(category.name, category.requirement, options.config) ) - details.push(` ${marker} ${category.name}: ${display}`) + details.push(` ${marker} ${category.name}: ${display} [capabilities: ${formatCapabilityResolutionLabel(category.capabilityDiagnostics?.resolutionMode)}]`) } details.push("") details.push("● = user override, ○ = provider fallback") diff --git a/src/cli/doctor/checks/model-resolution-types.ts b/src/cli/doctor/checks/model-resolution-types.ts index c0396d958..2e77fddd1 100644 --- a/src/cli/doctor/checks/model-resolution-types.ts +++ b/src/cli/doctor/checks/model-resolution-types.ts @@ -1,3 +1,4 @@ +import type { ModelCapabilitiesDiagnostics } from "../../../shared/model-capabilities" import type { ModelRequirement } from "../../../shared/model-requirements" export interface AgentResolutionInfo { @@ -7,6 +8,7 @@ export interface AgentResolutionInfo { userVariant?: string effectiveModel: string effectiveResolution: string + capabilityDiagnostics?: ModelCapabilitiesDiagnostics } export interface CategoryResolutionInfo { @@ -16,6 +18,7 @@ export interface CategoryResolutionInfo { userVariant?: string effectiveModel: string effectiveResolution: string + capabilityDiagnostics?: ModelCapabilitiesDiagnostics } export interface ModelResolutionInfo { diff --git a/src/cli/doctor/checks/model-resolution.test.ts b/src/cli/doctor/checks/model-resolution.test.ts index 902c92cfe..696e8c4d4 100644 --- a/src/cli/doctor/checks/model-resolution.test.ts +++ b/src/cli/doctor/checks/model-resolution.test.ts @@ -129,6 +129,19 @@ describe("model-resolution check", () => { expect(visual!.userOverride).toBe("google/gemini-3-flash-preview") expect(visual!.userVariant).toBe("high") }) + + it("attaches snapshot-backed capability diagnostics for built-in models", async () => { + const { getModelResolutionInfoWithOverrides } = await import("./model-resolution") + + const info = getModelResolutionInfoWithOverrides({}) + const sisyphus = info.agents.find((a) => a.name === "sisyphus") + + expect(sisyphus).toBeDefined() + expect(sisyphus!.capabilityDiagnostics).toMatchObject({ + resolutionMode: "snapshot-backed", + snapshot: { source: "bundled-snapshot" }, + }) + }) }) describe("checkModelResolution", () => { @@ -162,6 +175,23 @@ describe("model-resolution check", () => { expect(result.details!.some((d) => d.includes("Categories:"))).toBe(true) // Should have legend expect(result.details!.some((d) => d.includes("user override"))).toBe(true) + expect(result.details!.some((d) => d.includes("capabilities: snapshot-backed"))).toBe(true) + }) + + it("collects warnings when configured models rely on compatibility fallback", async () => { + const { collectCapabilityResolutionIssues, getModelResolutionInfoWithOverrides } = await import("./model-resolution") + + const info = getModelResolutionInfoWithOverrides({ + agents: { + oracle: { model: "custom/unknown-llm" }, + }, + }) + + const issues = collectCapabilityResolutionIssues(info) + + expect(issues).toHaveLength(1) + expect(issues[0]?.title).toContain("compatibility fallback") + expect(issues[0]?.description).toContain("oracle=custom/unknown-llm") }) }) diff --git a/src/cli/doctor/checks/model-resolution.ts b/src/cli/doctor/checks/model-resolution.ts index c9cc0c0b0..706b18f4b 100644 --- a/src/cli/doctor/checks/model-resolution.ts +++ b/src/cli/doctor/checks/model-resolution.ts @@ -1,4 +1,5 @@ import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "../../../shared/model-requirements" +import { getModelCapabilities } from "../../../shared/model-capabilities" import { CHECK_IDS, CHECK_NAMES } from "../constants" import type { CheckResult, DoctorIssue } from "../types" import { loadAvailableModelsFromCache } from "./model-resolution-cache" @@ -7,16 +8,36 @@ import { buildModelResolutionDetails } from "./model-resolution-details" import { buildEffectiveResolution, getEffectiveModel } from "./model-resolution-effective-model" import type { AgentResolutionInfo, CategoryResolutionInfo, ModelResolutionInfo, OmoConfig } from "./model-resolution-types" -export function getModelResolutionInfo(): ModelResolutionInfo { - const agents: AgentResolutionInfo[] = Object.entries(AGENT_MODEL_REQUIREMENTS).map(([name, requirement]) => ({ - name, - requirement, - effectiveModel: getEffectiveModel(requirement), - effectiveResolution: buildEffectiveResolution(requirement), - })) +function parseProviderModel(value: string): { providerID: string; modelID: string } | null { + const slashIndex = value.indexOf("/") + if (slashIndex <= 0 || slashIndex === value.length - 1) { + return null + } - const categories: CategoryResolutionInfo[] = Object.entries(CATEGORY_MODEL_REQUIREMENTS).map( - ([name, requirement]) => ({ + return { + providerID: value.slice(0, slashIndex), + modelID: value.slice(slashIndex + 1), + } +} + +function attachCapabilityDiagnostics(entry: T): T { + const parsed = parseProviderModel(entry.effectiveModel) + if (!parsed) { + return entry + } + + return { + ...entry, + capabilityDiagnostics: getModelCapabilities({ + providerID: parsed.providerID, + modelID: parsed.modelID, + }).diagnostics, + } +} + +export function getModelResolutionInfo(): ModelResolutionInfo { + const agents: AgentResolutionInfo[] = Object.entries(AGENT_MODEL_REQUIREMENTS).map(([name, requirement]) => + attachCapabilityDiagnostics({ name, requirement, effectiveModel: getEffectiveModel(requirement), @@ -24,6 +45,16 @@ export function getModelResolutionInfo(): ModelResolutionInfo { }) ) + const categories: CategoryResolutionInfo[] = Object.entries(CATEGORY_MODEL_REQUIREMENTS).map( + ([name, requirement]) => + attachCapabilityDiagnostics({ + name, + requirement, + effectiveModel: getEffectiveModel(requirement), + effectiveResolution: buildEffectiveResolution(requirement), + }) + ) + return { agents, categories } } @@ -31,34 +62,60 @@ export function getModelResolutionInfoWithOverrides(config: OmoConfig): ModelRes const agents: AgentResolutionInfo[] = Object.entries(AGENT_MODEL_REQUIREMENTS).map(([name, requirement]) => { const userOverride = config.agents?.[name]?.model const userVariant = config.agents?.[name]?.variant - return { + return attachCapabilityDiagnostics({ name, requirement, userOverride, userVariant, effectiveModel: getEffectiveModel(requirement, userOverride), effectiveResolution: buildEffectiveResolution(requirement, userOverride), - } + }) }) const categories: CategoryResolutionInfo[] = Object.entries(CATEGORY_MODEL_REQUIREMENTS).map( ([name, requirement]) => { const userOverride = config.categories?.[name]?.model const userVariant = config.categories?.[name]?.variant - return { + return attachCapabilityDiagnostics({ name, requirement, userOverride, userVariant, effectiveModel: getEffectiveModel(requirement, userOverride), effectiveResolution: buildEffectiveResolution(requirement, userOverride), - } + }) } ) return { agents, categories } } +export function collectCapabilityResolutionIssues(info: ModelResolutionInfo): DoctorIssue[] { + const issues: DoctorIssue[] = [] + const allEntries = [...info.agents, ...info.categories] + const fallbackEntries = allEntries.filter((entry) => { + const mode = entry.capabilityDiagnostics?.resolutionMode + return mode === "alias-backed" || mode === "heuristic-backed" || mode === "unknown" + }) + + if (fallbackEntries.length === 0) { + return issues + } + + const summary = fallbackEntries + .map((entry) => `${entry.name}=${entry.effectiveModel} (${entry.capabilityDiagnostics?.resolutionMode ?? "unknown"})`) + .join(", ") + + issues.push({ + title: "Configured models rely on compatibility fallback", + description: summary, + severity: "warning", + affects: fallbackEntries.map((entry) => entry.name), + }) + + return issues +} + export async function checkModels(): Promise { const config = loadOmoConfig() ?? {} const info = getModelResolutionInfoWithOverrides(config) @@ -75,6 +132,8 @@ export async function checkModels(): Promise { }) } + issues.push(...collectCapabilityResolutionIssues(info)) + const overrideCount = info.agents.filter((agent) => Boolean(agent.userOverride)).length + info.categories.filter((category) => Boolean(category.userOverride)).length diff --git a/src/cli/doctor/checks/system-loaded-version.test.ts b/src/cli/doctor/checks/system-loaded-version.test.ts index 3a89ee82d..de4c9391f 100644 --- a/src/cli/doctor/checks/system-loaded-version.test.ts +++ b/src/cli/doctor/checks/system-loaded-version.test.ts @@ -1,9 +1,10 @@ import { afterEach, describe, expect, it } from "bun:test" -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { dirname, join } from "node:path" import { PACKAGE_NAME } from "../constants" +import { resolveSymlink } from "../../../shared/file-utils" const systemLoadedVersionModulePath = "./system-loaded-version?system-loaded-version-test" @@ -104,6 +105,31 @@ describe("system loaded version", () => { expect(loadedVersion.expectedVersion).toBe("2.3.4") expect(loadedVersion.loadedVersion).toBe("2.3.4") }) + + it("resolves symlinked config directories before selecting install path", () => { + //#given + const realConfigDir = createTemporaryDirectory("omo-real-config-") + const symlinkBaseDir = createTemporaryDirectory("omo-symlink-base-") + const symlinkConfigDir = join(symlinkBaseDir, "config-link") + + symlinkSync(realConfigDir, symlinkConfigDir, process.platform === "win32" ? "junction" : "dir") + process.env.OPENCODE_CONFIG_DIR = symlinkConfigDir + + writeJson(join(realConfigDir, "package.json"), { + dependencies: { [PACKAGE_NAME]: "4.5.6" }, + }) + writeJson(join(realConfigDir, "node_modules", PACKAGE_NAME, "package.json"), { + version: "4.5.6", + }) + + //#when + const loadedVersion = getLoadedPluginVersion() + + //#then + expect(loadedVersion.cacheDir).toBe(resolveSymlink(symlinkConfigDir)) + expect(loadedVersion.expectedVersion).toBe("4.5.6") + expect(loadedVersion.loadedVersion).toBe("4.5.6") + }) }) describe("getSuggestedInstallTag", () => { diff --git a/src/cli/doctor/checks/system-loaded-version.ts b/src/cli/doctor/checks/system-loaded-version.ts index a62c0f97a..04e4a87d1 100644 --- a/src/cli/doctor/checks/system-loaded-version.ts +++ b/src/cli/doctor/checks/system-loaded-version.ts @@ -1,7 +1,7 @@ import { existsSync, readFileSync } from "node:fs" import { homedir } from "node:os" import { join } from "node:path" - +import { resolveSymlink } from "../../../shared/file-utils" import { getLatestVersion } from "../../../hooks/auto-update-checker/checker" import { extractChannel } from "../../../hooks/auto-update-checker" import { PACKAGE_NAME } from "../constants" @@ -36,6 +36,11 @@ function resolveOpenCodeCacheDir(): string { return platformDefault } +function resolveExistingDir(dirPath: string): string { + if (!existsSync(dirPath)) return dirPath + return resolveSymlink(dirPath) +} + function readPackageJson(filePath: string): PackageJsonShape | null { if (!existsSync(filePath)) return null @@ -55,12 +60,13 @@ function normalizeVersion(value: string | undefined): string | null { export function getLoadedPluginVersion(): LoadedVersionInfo { const configPaths = getOpenCodeConfigPaths({ binary: "opencode" }) - const cacheDir = resolveOpenCodeCacheDir() + const configDir = resolveExistingDir(configPaths.configDir) + const cacheDir = resolveExistingDir(resolveOpenCodeCacheDir()) const candidates = [ { - cacheDir: configPaths.configDir, - cachePackagePath: configPaths.packageJson, - installedPackagePath: join(configPaths.configDir, "node_modules", PACKAGE_NAME, "package.json"), + cacheDir: configDir, + cachePackagePath: join(configDir, "package.json"), + installedPackagePath: join(configDir, "node_modules", PACKAGE_NAME, "package.json"), }, { cacheDir, diff --git a/src/cli/doctor/checks/system.test.ts b/src/cli/doctor/checks/system.test.ts index 74e34038f..163031f13 100644 --- a/src/cli/doctor/checks/system.test.ts +++ b/src/cli/doctor/checks/system.test.ts @@ -1,9 +1,19 @@ +/// + import { beforeEach, describe, expect, it, mock } from "bun:test" +import { PLUGIN_NAME } from "../../../shared" +import type { PluginInfo } from "./system-plugin" + +type SystemModule = typeof import("./system") + +async function importFreshSystemModule(): Promise { + return import(`./system?test=${Date.now()}-${Math.random()}`) +} const mockFindOpenCodeBinary = mock(async () => ({ path: "/usr/local/bin/opencode" })) const mockGetOpenCodeVersion = mock(async () => "1.0.200") -const mockCompareVersions = mock(() => true) -const mockGetPluginInfo = mock(() => ({ +const mockCompareVersions = mock((_leftVersion?: string, _rightVersion?: string) => true) +const mockGetPluginInfo = mock((): PluginInfo => ({ registered: true, entry: "oh-my-opencode", isPinned: false, @@ -18,7 +28,8 @@ const mockGetLoadedPluginVersion = mock(() => ({ expectedVersion: "3.0.0", loadedVersion: "3.1.0", })) -const mockGetLatestPluginVersion = mock(async () => null) +const mockGetLatestPluginVersion = mock(async (_currentVersion: string | null) => null as string | null) +const mockGetSuggestedInstallTag = mock(() => "latest") mock.module("./system-binary", () => ({ findOpenCodeBinary: mockFindOpenCodeBinary, @@ -33,10 +44,9 @@ mock.module("./system-plugin", () => ({ mock.module("./system-loaded-version", () => ({ getLoadedPluginVersion: mockGetLoadedPluginVersion, getLatestPluginVersion: mockGetLatestPluginVersion, + getSuggestedInstallTag: mockGetSuggestedInstallTag, })) -const { checkSystem } = await import("./system?test") - describe("system check", () => { beforeEach(() => { mockFindOpenCodeBinary.mockReset() @@ -45,6 +55,7 @@ describe("system check", () => { mockGetPluginInfo.mockReset() mockGetLoadedPluginVersion.mockReset() mockGetLatestPluginVersion.mockReset() + mockGetSuggestedInstallTag.mockReset() mockFindOpenCodeBinary.mockResolvedValue({ path: "/usr/local/bin/opencode" }) mockGetOpenCodeVersion.mockResolvedValue("1.0.200") @@ -65,10 +76,14 @@ describe("system check", () => { loadedVersion: "3.1.0", }) mockGetLatestPluginVersion.mockResolvedValue(null) + mockGetSuggestedInstallTag.mockReturnValue("latest") }) describe("#given cache directory contains spaces", () => { it("uses a quoted cache directory in mismatch fix command", async () => { + //#given + const { checkSystem } = await importFreshSystemModule() + //#when const result = await checkSystem() @@ -87,9 +102,11 @@ describe("system check", () => { loadedVersion: "3.0.0-canary.1", }) mockGetLatestPluginVersion.mockResolvedValue("3.0.0-canary.2") - mockCompareVersions.mockImplementation((leftVersion: string, rightVersion: string) => { + mockGetSuggestedInstallTag.mockReturnValue("canary") + mockCompareVersions.mockImplementation((leftVersion?: string, rightVersion?: string) => { return !(leftVersion === "3.0.0-canary.1" && rightVersion === "3.0.0-canary.2") }) + const { checkSystem } = await importFreshSystemModule() //#when const result = await checkSystem() @@ -97,8 +114,94 @@ describe("system check", () => { //#then const outdatedIssue = result.issues.find((issue) => issue.title === "Loaded plugin is outdated") expect(outdatedIssue?.fix).toBe( - 'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-opencode@canary' + `Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add ${PLUGIN_NAME}@canary` ) }) }) + + describe("#given OpenCode plugin entry uses legacy package name", () => { + it("adds a warning for a bare legacy entry", async () => { + //#given + mockGetPluginInfo.mockReturnValue({ + registered: true, + entry: "oh-my-opencode", + isPinned: false, + pinnedVersion: null, + configPath: null, + isLocalDev: false, + }) + const { checkSystem } = await importFreshSystemModule() + + //#when + const result = await checkSystem() + + //#then + const legacyEntryIssue = result.issues.find((issue) => issue.title === "Using legacy package name") + expect(legacyEntryIssue?.severity).toBe("warning") + expect(legacyEntryIssue?.fix).toBe( + 'Update your opencode.json plugin entry: "oh-my-opencode" → "oh-my-openagent"' + ) + }) + + it("adds a warning for a version-pinned legacy entry", async () => { + //#given + mockGetPluginInfo.mockReturnValue({ + registered: true, + entry: "oh-my-opencode@3.0.0", + isPinned: true, + pinnedVersion: "3.0.0", + configPath: null, + isLocalDev: false, + }) + const { checkSystem } = await importFreshSystemModule() + + //#when + const result = await checkSystem() + + //#then + const legacyEntryIssue = result.issues.find((issue) => issue.title === "Using legacy package name") + expect(legacyEntryIssue?.severity).toBe("warning") + expect(legacyEntryIssue?.fix).toBe( + 'Update your opencode.json plugin entry: "oh-my-opencode@3.0.0" → "oh-my-openagent@3.0.0"' + ) + }) + + it("does not warn for a canonical plugin entry", async () => { + //#given + mockGetPluginInfo.mockReturnValue({ + registered: true, + entry: PLUGIN_NAME, + isPinned: false, + pinnedVersion: null, + configPath: null, + isLocalDev: false, + }) + const { checkSystem } = await importFreshSystemModule() + + //#when + const result = await checkSystem() + + //#then + expect(result.issues.some((issue) => issue.title === "Using legacy package name")).toBe(false) + }) + + it("does not warn for a local-dev legacy entry", async () => { + //#given + mockGetPluginInfo.mockReturnValue({ + registered: true, + entry: "oh-my-opencode", + isPinned: false, + pinnedVersion: null, + configPath: null, + isLocalDev: true, + }) + const { checkSystem } = await importFreshSystemModule() + + //#when + const result = await checkSystem() + + //#then + expect(result.issues.some((issue) => issue.title === "Using legacy package name")).toBe(false) + }) + }) }) diff --git a/src/cli/doctor/checks/system.ts b/src/cli/doctor/checks/system.ts index 41e49cd34..ed58ad04a 100644 --- a/src/cli/doctor/checks/system.ts +++ b/src/cli/doctor/checks/system.ts @@ -6,6 +6,7 @@ import { findOpenCodeBinary, getOpenCodeVersion, compareVersions } from "./syste import { getPluginInfo } from "./system-plugin" import { getLatestPluginVersion, getLoadedPluginVersion, getSuggestedInstallTag } from "./system-loaded-version" import { parseJsonc } from "../../../shared" +import { PLUGIN_NAME, LEGACY_PLUGIN_NAME } from "../../../shared/plugin-identity" function isConfigValid(configPath: string | null): boolean { if (!configPath) return true @@ -82,14 +83,30 @@ export async function checkSystem(): Promise { if (!pluginInfo.registered) { issues.push({ - title: "oh-my-opencode is not registered", + title: `${PLUGIN_NAME} is not registered`, description: "Plugin entry is missing from OpenCode configuration.", - fix: "Run: bunx oh-my-opencode install", + fix: `Run: bunx ${PLUGIN_NAME} install`, severity: "error", affects: ["all agents"], }) } + if (pluginInfo.entry && !pluginInfo.isLocalDev) { + const isLegacyName = pluginInfo.entry === LEGACY_PLUGIN_NAME + || pluginInfo.entry.startsWith(`${LEGACY_PLUGIN_NAME}@`) + + if (isLegacyName) { + const suggestedEntry = pluginInfo.entry.replace(LEGACY_PLUGIN_NAME, PLUGIN_NAME) + issues.push({ + title: "Using legacy package name", + description: `Your opencode.json references "${LEGACY_PLUGIN_NAME}" which has been renamed to "${PLUGIN_NAME}". The old name may stop working in a future release.`, + fix: `Update your opencode.json plugin entry: "${pluginInfo.entry}" → "${suggestedEntry}"`, + severity: "warning", + affects: ["plugin loading"], + }) + } + } + if (loadedInfo.expectedVersion && loadedInfo.loadedVersion && loadedInfo.expectedVersion !== loadedInfo.loadedVersion) { issues.push({ title: "Loaded plugin version mismatch", @@ -108,7 +125,7 @@ export async function checkSystem(): Promise { issues.push({ title: "Loaded plugin is outdated", description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`, - fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-opencode@${installTag}`, + fix: `Update: cd "${loadedInfo.cacheDir}" && bun add ${PLUGIN_NAME}@${installTag}`, severity: "warning", affects: ["plugin features"], }) diff --git a/src/cli/doctor/constants.ts b/src/cli/doctor/constants.ts index ff41f836e..9afaf5a88 100644 --- a/src/cli/doctor/constants.ts +++ b/src/cli/doctor/constants.ts @@ -1,4 +1,5 @@ import color from "picocolors" +import { PLUGIN_NAME } from "../../shared" export const SYMBOLS = { check: color.green("\u2713"), @@ -38,6 +39,6 @@ export const EXIT_CODES = { export const MIN_OPENCODE_VERSION = "1.0.150" -export const PACKAGE_NAME = "oh-my-opencode" +export const PACKAGE_NAME = PLUGIN_NAME export const OPENCODE_BINARIES = ["opencode", "opencode-desktop"] as const diff --git a/src/cli/install.test.ts b/src/cli/install.test.ts index e967ed6b4..94a891832 100644 --- a/src/cli/install.test.ts +++ b/src/cli/install.test.ts @@ -113,10 +113,10 @@ describe("install CLI - binary check behavior", () => { const configPath = join(tempDir, "opencode.json") expect(existsSync(configPath)).toBe(true) - // then opencode.json should have plugin entry const config = JSON.parse(readFileSync(configPath, "utf-8")) expect(config.plugin).toBeDefined() - expect(config.plugin.some((p: string) => p.includes("oh-my-opencode"))).toBe(true) + expect(config.plugin.some((p: string) => p.includes("oh-my-openagent"))).toBe(true) + expect(config.plugin.some((p: string) => p.includes("oh-my-opencode"))).toBe(false) // then exit code should be 0 (success) expect(exitCode).toBe(0) diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index cb6192f55..888f5336b 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -458,7 +458,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.hephaestus?.model).toBe("openai/gpt-5.3-codex") + expect(result.agents?.hephaestus?.model).toBe("openai/gpt-5.4") expect(result.agents?.hephaestus?.variant).toBe("medium") }) @@ -484,7 +484,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.hephaestus?.model).toBe("opencode/gpt-5.3-codex") + expect(result.agents?.hephaestus?.model).toBe("opencode/gpt-5.4") expect(result.agents?.hephaestus?.variant).toBe("medium") }) diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index f0b044978..331c97142 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -55,7 +55,7 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) { if (role === "librarian") { if (avail.opencodeGo) { - agents[role] = { model: "opencode-go/minimax-m2.5" } + agents[role] = { model: "opencode-go/minimax-m2.7" } } else if (avail.zai) { agents[role] = { model: ZAI_MODEL } } @@ -68,7 +68,7 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { } else if (avail.opencodeZen) { agents[role] = { model: "opencode/claude-haiku-4-5" } } else if (avail.opencodeGo) { - agents[role] = { model: "opencode-go/minimax-m2.5" } + agents[role] = { model: "opencode-go/minimax-m2.7" } } else if (avail.copilot) { agents[role] = { model: "github-copilot/gpt-5-mini" } } else { diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index ef384ab5e..2b9cae55b 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -53,8 +53,8 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toEqual({ model: "opencode-go/minimax-m2.5" }) - expect(result.agents?.librarian).toEqual({ model: "opencode-go/minimax-m2.5" }) + expect(result.agents?.explore).toEqual({ model: "opencode-go/minimax-m2.7" }) + expect(result.agents?.librarian).toEqual({ model: "opencode-go/minimax-m2.7" }) expect(result.categories?.quick).toEqual({ model: "openai/gpt-5.4-mini" }) }) }) diff --git a/src/cli/refresh-model-capabilities.test.ts b/src/cli/refresh-model-capabilities.test.ts new file mode 100644 index 000000000..800cf7e54 --- /dev/null +++ b/src/cli/refresh-model-capabilities.test.ts @@ -0,0 +1,114 @@ +import { describe, expect, it, mock } from "bun:test" + +import { refreshModelCapabilities } from "./refresh-model-capabilities" + +describe("refreshModelCapabilities", () => { + it("uses config source_url when CLI override is absent", async () => { + const loadConfig = mock(() => ({ + model_capabilities: { + source_url: "https://mirror.example/api.json", + }, + })) + const refreshCache = mock(async () => ({ + generatedAt: "2026-03-25T00:00:00.000Z", + sourceUrl: "https://mirror.example/api.json", + models: { + "gpt-5.4": { id: "gpt-5.4" }, + }, + })) + let stdout = "" + + const exitCode = await refreshModelCapabilities( + { directory: "/repo", json: false }, + { + loadConfig, + refreshCache, + stdout: { + write: (chunk: string) => { + stdout += chunk + return true + }, + } as never, + stderr: { + write: () => true, + } as never, + }, + ) + + expect(exitCode).toBe(0) + expect(loadConfig).toHaveBeenCalledWith("/repo", null) + expect(refreshCache).toHaveBeenCalledWith({ + sourceUrl: "https://mirror.example/api.json", + }) + expect(stdout).toContain("Refreshed model capabilities cache (1 models)") + }) + + it("CLI sourceUrl overrides config and supports json output", async () => { + const refreshCache = mock(async () => ({ + generatedAt: "2026-03-25T00:00:00.000Z", + sourceUrl: "https://override.example/api.json", + models: { + "gpt-5.4": { id: "gpt-5.4" }, + "claude-opus-4-6": { id: "claude-opus-4-6" }, + }, + })) + let stdout = "" + + const exitCode = await refreshModelCapabilities( + { + directory: "/repo", + json: true, + sourceUrl: "https://override.example/api.json", + }, + { + loadConfig: () => ({}), + refreshCache, + stdout: { + write: (chunk: string) => { + stdout += chunk + return true + }, + } as never, + stderr: { + write: () => true, + } as never, + }, + ) + + expect(exitCode).toBe(0) + expect(refreshCache).toHaveBeenCalledWith({ + sourceUrl: "https://override.example/api.json", + }) + expect(JSON.parse(stdout)).toEqual({ + sourceUrl: "https://override.example/api.json", + generatedAt: "2026-03-25T00:00:00.000Z", + modelCount: 2, + }) + }) + + it("returns exit code 1 when refresh fails", async () => { + let stderr = "" + + const exitCode = await refreshModelCapabilities( + { directory: "/repo" }, + { + loadConfig: () => ({}), + refreshCache: async () => { + throw new Error("boom") + }, + stdout: { + write: () => true, + } as never, + stderr: { + write: (chunk: string) => { + stderr += chunk + return true + }, + } as never, + }, + ) + + expect(exitCode).toBe(1) + expect(stderr).toContain("Failed to refresh model capabilities cache") + }) +}) diff --git a/src/cli/refresh-model-capabilities.ts b/src/cli/refresh-model-capabilities.ts new file mode 100644 index 000000000..fc9ff1282 --- /dev/null +++ b/src/cli/refresh-model-capabilities.ts @@ -0,0 +1,51 @@ +import { loadPluginConfig } from "../plugin-config" +import { refreshModelCapabilitiesCache } from "../shared/model-capabilities-cache" + +export type RefreshModelCapabilitiesOptions = { + directory?: string + json?: boolean + sourceUrl?: string +} + +type RefreshModelCapabilitiesDeps = { + loadConfig?: typeof loadPluginConfig + refreshCache?: typeof refreshModelCapabilitiesCache + stdout?: Pick + stderr?: Pick +} + +export async function refreshModelCapabilities( + options: RefreshModelCapabilitiesOptions, + deps: RefreshModelCapabilitiesDeps = {}, +): Promise { + const directory = options.directory ?? process.cwd() + const loadConfig = deps.loadConfig ?? loadPluginConfig + const refreshCache = deps.refreshCache ?? refreshModelCapabilitiesCache + const stdout = deps.stdout ?? process.stdout + const stderr = deps.stderr ?? process.stderr + + try { + const config = loadConfig(directory, null) + const sourceUrl = options.sourceUrl ?? config.model_capabilities?.source_url + const snapshot = await refreshCache({ sourceUrl }) + + const summary = { + sourceUrl: snapshot.sourceUrl, + generatedAt: snapshot.generatedAt, + modelCount: Object.keys(snapshot.models).length, + } + + if (options.json) { + stdout.write(`${JSON.stringify(summary, null, 2)}\n`) + } else { + stdout.write( + `Refreshed model capabilities cache (${summary.modelCount} models) from ${summary.sourceUrl}\n`, + ) + } + + return 0 + } catch (error) { + stderr.write(`Failed to refresh model capabilities cache: ${String(error)}\n`) + return 1 + } +} diff --git a/src/cli/tui-installer.ts b/src/cli/tui-installer.ts index 410416842..49fc0c5db 100644 --- a/src/cli/tui-installer.ts +++ b/src/cli/tui-installer.ts @@ -1,5 +1,6 @@ import * as p from "@clack/prompts" import color from "picocolors" +import { PLUGIN_NAME } from "../shared" import type { InstallArgs } from "./types" import { addPluginToOpenCodeConfig, @@ -43,7 +44,7 @@ export async function runTuiInstaller(args: InstallArgs, version: string): Promi const config = await promptInstallConfig(detected) if (!config) return 1 - spinner.start("Adding oh-my-opencode to OpenCode config") + spinner.start(`Adding ${PLUGIN_NAME} to OpenCode config`) const pluginResult = await addPluginToOpenCodeConfig(version) if (!pluginResult.success) { spinner.stop(`Failed to add plugin: ${pluginResult.error}`) @@ -52,7 +53,7 @@ export async function runTuiInstaller(args: InstallArgs, version: string): Promi } spinner.stop(`Plugin added to ${color.cyan(pluginResult.configPath)}`) - spinner.start("Writing oh-my-opencode configuration") + spinner.start(`Writing ${PLUGIN_NAME} configuration`) const omoResult = writeOmoConfig(config) if (!omoResult.success) { spinner.stop(`Failed to write config: ${omoResult.error}`) diff --git a/src/config/index.ts b/src/config/index.ts index 2f7f98578..57a347d3a 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -19,5 +19,6 @@ export type { SisyphusConfig, SisyphusTasksConfig, RuntimeFallbackConfig, + ModelCapabilitiesConfig, FallbackModels, } from "./schema" diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index acc45e0bd..7f4ad615f 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -147,6 +147,37 @@ describe("disabled_mcps schema", () => { }) }) +describe("OhMyOpenCodeConfigSchema - model_capabilities", () => { + test("accepts valid model capabilities config", () => { + const input = { + model_capabilities: { + enabled: true, + auto_refresh_on_start: true, + refresh_timeout_ms: 5000, + source_url: "https://models.dev/api.json", + }, + } + + const result = OhMyOpenCodeConfigSchema.safeParse(input) + + expect(result.success).toBe(true) + if (result.success) { + expect(result.data.model_capabilities).toEqual(input.model_capabilities) + } + }) + + test("rejects invalid model capabilities config", () => { + const result = OhMyOpenCodeConfigSchema.safeParse({ + model_capabilities: { + refresh_timeout_ms: -1, + source_url: "not-a-url", + }, + }) + + expect(result.success).toBe(false) + }) +}) + describe("AgentOverrideConfigSchema", () => { describe("category field", () => { test("accepts category as optional string", () => { diff --git a/src/config/schema.ts b/src/config/schema.ts index bcb36a175..04dd0b15b 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -13,6 +13,7 @@ export * from "./schema/fallback-models" export * from "./schema/git-env-prefix" export * from "./schema/git-master" export * from "./schema/hooks" +export * from "./schema/model-capabilities" export * from "./schema/notification" export * from "./schema/oh-my-opencode-config" export * from "./schema/ralph-loop" diff --git a/src/config/schema/model-capabilities.ts b/src/config/schema/model-capabilities.ts new file mode 100644 index 000000000..76adc6522 --- /dev/null +++ b/src/config/schema/model-capabilities.ts @@ -0,0 +1,10 @@ +import { z } from "zod" + +export const ModelCapabilitiesConfigSchema = z.object({ + enabled: z.boolean().optional(), + auto_refresh_on_start: z.boolean().optional(), + refresh_timeout_ms: z.number().int().positive().optional(), + source_url: z.string().url().optional(), +}) + +export type ModelCapabilitiesConfig = z.infer diff --git a/src/config/schema/oh-my-opencode-config.ts b/src/config/schema/oh-my-opencode-config.ts index ea7e479c5..434bfe7ee 100644 --- a/src/config/schema/oh-my-opencode-config.ts +++ b/src/config/schema/oh-my-opencode-config.ts @@ -13,6 +13,7 @@ import { ExperimentalConfigSchema } from "./experimental" import { GitMasterConfigSchema } from "./git-master" import { NotificationConfigSchema } from "./notification" import { OpenClawConfigSchema } from "./openclaw" +import { ModelCapabilitiesConfigSchema } from "./model-capabilities" import { RalphLoopConfigSchema } from "./ralph-loop" import { RuntimeFallbackConfigSchema } from "./runtime-fallback" import { SkillsConfigSchema } from "./skills" @@ -56,6 +57,7 @@ export const OhMyOpenCodeConfigSchema = z.object({ runtime_fallback: z.union([z.boolean(), RuntimeFallbackConfigSchema]).optional(), background_task: BackgroundTaskConfigSchema.optional(), notification: NotificationConfigSchema.optional(), + model_capabilities: ModelCapabilitiesConfigSchema.optional(), openclaw: OpenClawConfigSchema.optional(), babysitting: BabysittingConfigSchema.optional(), git_master: GitMasterConfigSchema.optional(), diff --git a/src/features/background-agent/fallback-retry-handler.test.ts b/src/features/background-agent/fallback-retry-handler.test.ts index 03cd2b16f..825f72a56 100644 --- a/src/features/background-agent/fallback-retry-handler.test.ts +++ b/src/features/background-agent/fallback-retry-handler.test.ts @@ -1,4 +1,4 @@ -import { describe, test, expect, mock, beforeEach } from "bun:test" +import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test" mock.module("../../shared", () => ({ log: mock(() => {}), @@ -82,6 +82,10 @@ function createDefaultArgs(taskOverrides: Partial = {}) { } describe("tryFallbackRetry", () => { + afterAll(() => { + mock.restore() + }) + beforeEach(() => { ;(shouldRetryError as any).mockImplementation(() => true) ;(selectFallbackProvider as any).mockImplementation((providers: string[]) => providers[0]) @@ -274,8 +278,8 @@ describe("tryFallbackRetry", () => { describe("#given disconnected fallback providers with connected preferred provider", () => { test("keeps fallback entry and selects connected preferred provider", () => { - ;(readProviderModelsCache as any).mockReturnValue({ connected: ["provider-a"] }) - ;(selectFallbackProvider as any).mockImplementation( + ;(readProviderModelsCache as any).mockReturnValueOnce({ connected: ["provider-a"] }) + ;(selectFallbackProvider as any).mockImplementationOnce( (_providers: string[], preferredProviderID?: string) => preferredProviderID ?? "provider-b", ) diff --git a/src/features/claude-code-command-loader/loader.test.ts b/src/features/claude-code-command-loader/loader.test.ts new file mode 100644 index 000000000..be7928d3f --- /dev/null +++ b/src/features/claude-code-command-loader/loader.test.ts @@ -0,0 +1,125 @@ +import { execFileSync } from "node:child_process" +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { loadOpencodeGlobalCommands, loadOpencodeProjectCommands } from "./loader" + +const TEST_DIR = join(tmpdir(), `claude-code-command-loader-${Date.now()}`) + +function writeCommand(directory: string, name: string, description: string): void { + mkdirSync(directory, { recursive: true }) + writeFileSync( + join(directory, `${name}.md`), + `---\ndescription: ${description}\n---\nRun ${name}.\n`, + ) +} + +describe("claude-code command loader", () => { + let originalOpencodeConfigDir: string | undefined + + beforeEach(() => { + mkdirSync(TEST_DIR, { recursive: true }) + originalOpencodeConfigDir = process.env.OPENCODE_CONFIG_DIR + }) + + afterEach(() => { + if (originalOpencodeConfigDir === undefined) { + delete process.env.OPENCODE_CONFIG_DIR + } else { + process.env.OPENCODE_CONFIG_DIR = originalOpencodeConfigDir + } + rmSync(TEST_DIR, { recursive: true, force: true }) + }) + + it("#given a parent .opencode/commands directory #when loadOpencodeProjectCommands is called from child directory #then it loads the ancestor command", async () => { + // given + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "apps", "desktop") + writeCommand(join(projectDir, ".opencode", "commands"), "ancestor", "Ancestor command") + + // when + const commands = await loadOpencodeProjectCommands(childDir) + + // then + expect(commands.ancestor?.description).toBe("(opencode-project) Ancestor command") + }) + + it("#given a .opencode/command directory #when loadOpencodeProjectCommands is called #then it loads the singular alias directory", async () => { + // given + writeCommand(join(TEST_DIR, ".opencode", "command"), "singular", "Singular command") + + // when + const commands = await loadOpencodeProjectCommands(TEST_DIR) + + // then + expect(commands.singular?.description).toBe("(opencode-project) Singular command") + }) + + it("#given duplicate project command names across ancestors #when loadOpencodeProjectCommands is called #then the nearest directory wins", async () => { + // given + const projectRoot = join(TEST_DIR, "project") + const childDir = join(projectRoot, "apps", "desktop") + const ancestorDir = join(TEST_DIR, ".opencode", "commands") + const projectDir = join(projectRoot, ".opencode", "commands") + writeCommand(ancestorDir, "duplicate", "Ancestor command") + writeCommand(projectDir, "duplicate", "Nearest command") + + // when + const commands = await loadOpencodeProjectCommands(childDir) + + // then + expect(commands.duplicate?.description).toBe("(opencode-project) Nearest command") + }) + + it("#given a global .opencode/commands directory #when loadOpencodeGlobalCommands is called #then it loads the plural alias directory", async () => { + // given + const opencodeConfigDir = join(TEST_DIR, "opencode-config") + process.env.OPENCODE_CONFIG_DIR = opencodeConfigDir + writeCommand(join(opencodeConfigDir, "commands"), "global-plural", "Global plural command") + + // when + const commands = await loadOpencodeGlobalCommands() + + // then + expect(commands["global-plural"]?.description).toBe("(opencode) Global plural command") + }) + + it("#given duplicate global command names across profile and parent dirs #when loadOpencodeGlobalCommands is called #then the profile dir wins", async () => { + // given + const opencodeRootDir = join(TEST_DIR, "opencode-root") + const profileConfigDir = join(opencodeRootDir, "profiles", "codex") + process.env.OPENCODE_CONFIG_DIR = profileConfigDir + writeCommand(join(opencodeRootDir, "commands"), "duplicate-global", "Parent global command") + writeCommand(join(profileConfigDir, "commands"), "duplicate-global", "Profile global command") + + // when + const commands = await loadOpencodeGlobalCommands() + + // then + expect(commands["duplicate-global"]?.description).toBe("(opencode) Profile global command") + }) + + it("#given nested project opencode commands in a worktree #when loadOpencodeProjectCommands is called #then it preserves slash names and stops at the worktree root", async () => { + // given + const repositoryDir = join(TEST_DIR, "repo") + const nestedDirectory = join(repositoryDir, "packages", "app", "src") + mkdirSync(nestedDirectory, { recursive: true }) + execFileSync("git", ["init"], { + cwd: repositoryDir, + stdio: ["ignore", "ignore", "ignore"], + }) + writeCommand(join(repositoryDir, ".opencode", "commands", "deploy"), "staging", "Deploy staging") + writeCommand(join(repositoryDir, ".opencode", "command"), "release", "Release command") + writeCommand(join(TEST_DIR, ".opencode", "commands"), "outside", "Outside command") + + // when + const commands = await loadOpencodeProjectCommands(nestedDirectory) + + // then + expect(commands["deploy/staging"]?.description).toBe("(opencode-project) Deploy staging") + expect(commands.release?.description).toBe("(opencode-project) Release command") + expect(commands.outside).toBeUndefined() + expect(commands["deploy:staging"]).toBeUndefined() + }) +}) diff --git a/src/features/claude-code-command-loader/loader.ts b/src/features/claude-code-command-loader/loader.ts index adf2cc4c1..b052f56bd 100644 --- a/src/features/claude-code-command-loader/loader.ts +++ b/src/features/claude-code-command-loader/loader.ts @@ -3,7 +3,11 @@ import { join, basename } from "path" import { parseFrontmatter } from "../../shared/frontmatter" import { sanitizeModelField } from "../../shared/model-sanitizer" import { isMarkdownFile } from "../../shared/file-utils" -import { getClaudeConfigDir, getOpenCodeConfigDir } from "../../shared" +import { + findProjectOpencodeCommandDirs, + getClaudeConfigDir, + getOpenCodeCommandDirs, +} from "../../shared" import { log } from "../../shared/logger" import type { CommandScope, CommandDefinition, CommandFrontmatter, LoadedCommand } from "./types" @@ -46,7 +50,7 @@ async function loadCommandsFromDir( if (entry.isDirectory()) { if (entry.name.startsWith(".")) continue const subDirPath = join(commandsDir, entry.name) - const subPrefix = prefix ? `${prefix}:${entry.name}` : entry.name + const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix) commands.push(...subCommands) continue @@ -56,7 +60,7 @@ async function loadCommandsFromDir( const commandPath = join(commandsDir, entry.name) const baseCommandName = basename(entry.name, ".md") - const commandName = prefix ? `${prefix}:${baseCommandName}` : baseCommandName + const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName try { const content = await fs.readFile(commandPath, "utf-8") @@ -99,9 +103,25 @@ $ARGUMENTS return commands } +function deduplicateLoadedCommandsByName(commands: LoadedCommand[]): LoadedCommand[] { + const seen = new Set() + const deduplicatedCommands: LoadedCommand[] = [] + + for (const command of commands) { + if (seen.has(command.name)) { + continue + } + + seen.add(command.name) + deduplicatedCommands.push(command) + } + + return deduplicatedCommands +} + function commandsToRecord(commands: LoadedCommand[]): Record { const result: Record = {} - for (const cmd of commands) { + for (const cmd of deduplicateLoadedCommandsByName(commands)) { const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = cmd.definition result[cmd.name] = openCodeCompatible as CommandDefinition } @@ -121,16 +141,21 @@ export async function loadProjectCommands(directory?: string): Promise> { - const configDir = getOpenCodeConfigDir({ binary: "opencode" }) - const opencodeCommandsDir = join(configDir, "command") - const commands = await loadCommandsFromDir(opencodeCommandsDir, "opencode") - return commandsToRecord(commands) + const opencodeCommandDirs = getOpenCodeCommandDirs({ binary: "opencode" }) + const allCommands = await Promise.all( + opencodeCommandDirs.map((commandsDir) => loadCommandsFromDir(commandsDir, "opencode")), + ) + return commandsToRecord(allCommands.flat()) } export async function loadOpencodeProjectCommands(directory?: string): Promise> { - const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "command") - const commands = await loadCommandsFromDir(opencodeProjectDir, "opencode-project") - return commandsToRecord(commands) + const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd()) + const allCommands = await Promise.all( + opencodeProjectDirs.map((commandsDir) => + loadCommandsFromDir(commandsDir, "opencode-project"), + ), + ) + return commandsToRecord(allCommands.flat()) } export async function loadAllCommands(directory?: string): Promise> { diff --git a/src/features/claude-code-plugin-loader/discovery.test.ts b/src/features/claude-code-plugin-loader/discovery.test.ts new file mode 100644 index 000000000..d42286579 --- /dev/null +++ b/src/features/claude-code-plugin-loader/discovery.test.ts @@ -0,0 +1,139 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" + +import { discoverInstalledPlugins } from "./discovery" + +const originalClaudePluginsHome = process.env.CLAUDE_PLUGINS_HOME +const temporaryDirectories: string[] = [] + +function createTemporaryDirectory(prefix: string): string { + const directory = mkdtempSync(join(tmpdir(), prefix)) + temporaryDirectories.push(directory) + return directory +} + +describe("discoverInstalledPlugins", () => { + beforeEach(() => { + const pluginsHome = createTemporaryDirectory("omo-claude-plugins-") + process.env.CLAUDE_PLUGINS_HOME = pluginsHome + }) + + afterEach(() => { + if (originalClaudePluginsHome === undefined) { + delete process.env.CLAUDE_PLUGINS_HOME + } else { + process.env.CLAUDE_PLUGINS_HOME = originalClaudePluginsHome + } + + for (const directory of temporaryDirectories.splice(0)) { + rmSync(directory, { recursive: true, force: true }) + } + }) + + it("preserves scoped package name from npm plugin keys", () => { + //#given + const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string + const installPath = join(createTemporaryDirectory("omo-plugin-install-"), "@myorg", "my-plugin") + mkdirSync(installPath, { recursive: true }) + + const databasePath = join(pluginsHome, "installed_plugins.json") + writeFileSync( + databasePath, + JSON.stringify({ + version: 2, + plugins: { + "@myorg/my-plugin@1.0.0": [ + { + scope: "user", + installPath, + version: "1.0.0", + installedAt: "2026-03-25T00:00:00Z", + lastUpdated: "2026-03-25T00:00:00Z", + }, + ], + }, + }), + "utf-8", + ) + + //#when + const discovered = discoverInstalledPlugins() + + //#then + expect(discovered.errors).toHaveLength(0) + expect(discovered.plugins).toHaveLength(1) + expect(discovered.plugins[0]?.name).toBe("@myorg/my-plugin") + }) + + it("derives package name from file URL plugin keys", () => { + //#given + const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string + const installPath = join(createTemporaryDirectory("omo-plugin-install-"), "oh-my-opencode") + mkdirSync(installPath, { recursive: true }) + + const databasePath = join(pluginsHome, "installed_plugins.json") + writeFileSync( + databasePath, + JSON.stringify({ + version: 2, + plugins: { + "file:///D:/configs/user-configs/.config/opencode/node_modules/oh-my-opencode@latest": [ + { + scope: "user", + installPath, + version: "3.10.0", + installedAt: "2026-03-20T00:00:00Z", + lastUpdated: "2026-03-20T00:00:00Z", + }, + ], + }, + }), + "utf-8", + ) + + //#when + const discovered = discoverInstalledPlugins() + + //#then + expect(discovered.errors).toHaveLength(0) + expect(discovered.plugins).toHaveLength(1) + expect(discovered.plugins[0]?.name).toBe("oh-my-opencode") + }) + + it("derives canonical package name from npm plugin keys", () => { + //#given + const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string + const installPath = join(createTemporaryDirectory("omo-plugin-install-"), "oh-my-openagent") + mkdirSync(installPath, { recursive: true }) + + const databasePath = join(pluginsHome, "installed_plugins.json") + writeFileSync( + databasePath, + JSON.stringify({ + version: 2, + plugins: { + "oh-my-openagent@3.13.1": [ + { + scope: "user", + installPath, + version: "3.13.1", + installedAt: "2026-03-26T00:00:00Z", + lastUpdated: "2026-03-26T00:00:00Z", + }, + ], + }, + }), + "utf-8", + ) + + //#when + const discovered = discoverInstalledPlugins() + + //#then + expect(discovered.errors).toHaveLength(0) + expect(discovered.plugins).toHaveLength(1) + expect(discovered.plugins[0]?.name).toBe("oh-my-openagent") + }) +}) diff --git a/src/features/claude-code-plugin-loader/discovery.ts b/src/features/claude-code-plugin-loader/discovery.ts index f2ec3d0be..d4d9bb577 100644 --- a/src/features/claude-code-plugin-loader/discovery.ts +++ b/src/features/claude-code-plugin-loader/discovery.ts @@ -1,6 +1,7 @@ import { existsSync, readFileSync } from "fs" import { homedir } from "os" -import { join } from "path" +import { basename, join } from "path" +import { fileURLToPath } from "url" import { log } from "../../shared/logger" import type { InstalledPluginsDatabase, @@ -79,8 +80,34 @@ function loadPluginManifest(installPath: string): PluginManifest | null { } function derivePluginNameFromKey(pluginKey: string): string { - const atIndex = pluginKey.indexOf("@") - return atIndex > 0 ? pluginKey.substring(0, atIndex) : pluginKey + const keyWithoutSource = pluginKey.startsWith("npm:") ? pluginKey.slice(4) : pluginKey + + let versionSeparator: number + if (keyWithoutSource.startsWith("@")) { + const scopeEnd = keyWithoutSource.indexOf("/") + versionSeparator = scopeEnd > 0 ? keyWithoutSource.indexOf("@", scopeEnd) : -1 + } else { + versionSeparator = keyWithoutSource.lastIndexOf("@") + } + const keyWithoutVersion = versionSeparator > 0 ? keyWithoutSource.slice(0, versionSeparator) : keyWithoutSource + + if (keyWithoutVersion.startsWith("file://")) { + try { + return basename(fileURLToPath(keyWithoutVersion)) + } catch { + return basename(keyWithoutVersion) + } + } + + if (keyWithoutVersion.startsWith("@") && keyWithoutVersion.includes("/")) { + return keyWithoutVersion + } + + if (keyWithoutVersion.includes("/") || keyWithoutVersion.includes("\\")) { + return basename(keyWithoutVersion) + } + + return keyWithoutVersion } function isPluginEnabled( diff --git a/src/features/opencode-skill-loader/config-source-discovery.test.ts b/src/features/opencode-skill-loader/config-source-discovery.test.ts index d10303ce0..091118ce6 100644 --- a/src/features/opencode-skill-loader/config-source-discovery.test.ts +++ b/src/features/opencode-skill-loader/config-source-discovery.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test" import { mkdirSync, rmSync, writeFileSync } from "fs" import { join } from "path" -import { tmpdir } from "os" +import { homedir, tmpdir } from "os" import { SkillsConfigSchema } from "../../config/schema/skills" import { discoverConfigSourceSkills, normalizePathForGlob } from "./config-source-discovery" @@ -69,6 +69,28 @@ describe("config source discovery", () => { expect(names).not.toContain("skip/skipped-skill") }) + it("loads skills from ~/ sources path", async () => { + // given + const homeSkillsDir = join(homedir(), `.omo-config-source-${Date.now()}`) + writeSkill(join(homeSkillsDir, "tilde-skill"), "tilde-skill", "Loaded from tilde path") + const config = SkillsConfigSchema.parse({ + sources: [{ path: `~/${homeSkillsDir.split(homedir())[1]?.replace(/^\//, "")}`, recursive: true }], + }) + + try { + // when + const skills = await discoverConfigSourceSkills({ + config, + configDir: join(TEST_DIR, "config"), + }) + + // then + expect(skills.some((skill) => skill.name === "tilde-skill")).toBe(true) + } finally { + rmSync(homeSkillsDir, { recursive: true, force: true }) + } + }) + it("normalizes windows separators before glob matching", () => { // given const windowsPath = "keep\\nested\\SKILL.md" diff --git a/src/features/opencode-skill-loader/config-source-discovery.ts b/src/features/opencode-skill-loader/config-source-discovery.ts index df3ee653e..b290c8b30 100644 --- a/src/features/opencode-skill-loader/config-source-discovery.ts +++ b/src/features/opencode-skill-loader/config-source-discovery.ts @@ -1,4 +1,5 @@ import { promises as fs } from "fs" +import { homedir } from "os" import { dirname, extname, isAbsolute, join, relative } from "path" import picomatch from "picomatch" import type { SkillsConfig } from "../../config/schema" @@ -15,6 +16,14 @@ function isHttpUrl(path: string): boolean { } function toAbsolutePath(path: string, configDir: string): string { + if (path === "~") { + return homedir() + } + + if (path.startsWith("~/")) { + return join(homedir(), path.slice(2)) + } + if (isAbsolute(path)) { return path } diff --git a/src/features/opencode-skill-loader/loader.test.ts b/src/features/opencode-skill-loader/loader.test.ts index 7aecb801f..c5042e0b1 100644 --- a/src/features/opencode-skill-loader/loader.test.ts +++ b/src/features/opencode-skill-loader/loader.test.ts @@ -615,5 +615,92 @@ Skill body. expect(skill).toBeDefined() expect(skill?.scope).toBe("project") }) + + it("#given a skill in ancestor .agents/skills/ #when discoverProjectAgentsSkills is called from child directory #then it discovers the ancestor skill", async () => { + // given + const skillContent = `--- +name: ancestor-agent-skill +description: A skill from ancestor .agents/skills directory +--- +Skill body. +` + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "apps", "worker") + const agentsProjectSkillsDir = join(projectDir, ".agents", "skills") + const skillDir = join(agentsProjectSkillsDir, "ancestor-agent-skill") + mkdirSync(childDir, { recursive: true }) + mkdirSync(skillDir, { recursive: true }) + writeFileSync(join(skillDir, "SKILL.md"), skillContent) + + // when + const { discoverProjectAgentsSkills } = await import("./loader") + const skills = await discoverProjectAgentsSkills(childDir) + const skill = skills.find((candidate) => candidate.name === "ancestor-agent-skill") + + // then + expect(skill).toBeDefined() + expect(skill?.scope).toBe("project") + }) + }) + + describe("opencode project skill discovery", () => { + it("#given a skill in ancestor .opencode/skills/ #when discoverOpencodeProjectSkills is called from child directory #then it discovers the ancestor skill", async () => { + // given + const skillContent = `--- +name: ancestor-opencode-skill +description: A skill from ancestor .opencode/skills directory +--- +Skill body. +` + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "packages", "cli") + const skillsDir = join(projectDir, ".opencode", "skills", "ancestor-opencode-skill") + mkdirSync(childDir, { recursive: true }) + mkdirSync(skillsDir, { recursive: true }) + writeFileSync(join(skillsDir, "SKILL.md"), skillContent) + + // when + const { discoverOpencodeProjectSkills } = await import("./loader") + const skills = await discoverOpencodeProjectSkills(childDir) + const skill = skills.find((candidate) => candidate.name === "ancestor-opencode-skill") + + // then + expect(skill).toBeDefined() + expect(skill?.scope).toBe("opencode-project") + }) + + it("#given a skill in .opencode/skill/ #when discoverOpencodeProjectSkills is called #then it discovers the singular alias directory", async () => { + // given + const skillContent = `--- +name: singular-opencode-skill +description: A skill from .opencode/skill directory +--- +Skill body. +` + const singularSkillDir = join( + TEST_DIR, + ".opencode", + "skill", + "singular-opencode-skill", + ) + mkdirSync(singularSkillDir, { recursive: true }) + writeFileSync(join(singularSkillDir, "SKILL.md"), skillContent) + + // when + const { discoverOpencodeProjectSkills } = await import("./loader") + const originalCwd = process.cwd() + process.chdir(TEST_DIR) + + try { + const skills = await discoverOpencodeProjectSkills() + const skill = skills.find((candidate) => candidate.name === "singular-opencode-skill") + + // then + expect(skill).toBeDefined() + expect(skill?.scope).toBe("opencode-project") + } finally { + process.chdir(originalCwd) + } + }) }) }) diff --git a/src/features/opencode-skill-loader/loader.ts b/src/features/opencode-skill-loader/loader.ts index 205267e3e..6f0c44c3b 100644 --- a/src/features/opencode-skill-loader/loader.ts +++ b/src/features/opencode-skill-loader/loader.ts @@ -3,6 +3,11 @@ import { homedir } from "os" import { getClaudeConfigDir } from "../../shared/claude-config-dir" import { getOpenCodeConfigDir } from "../../shared/opencode-config-dir" import { getOpenCodeSkillDirs } from "../../shared/opencode-command-dirs" +import { + findProjectAgentsSkillDirs, + findProjectClaudeSkillDirs, + findProjectOpencodeSkillDirs, +} from "../../shared/project-discovery-dirs" import type { CommandDefinition } from "../claude-code-command-loader/types" import type { LoadedSkill } from "./types" import { skillsToCommandDefinitionRecord } from "./skill-definition-record" @@ -16,9 +21,11 @@ export async function loadUserSkills(): Promise> { - const projectSkillsDir = join(directory ?? process.cwd(), ".claude", "skills") - const skills = await loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" }) - return skillsToCommandDefinitionRecord(skills) + const projectSkillDirs = findProjectClaudeSkillDirs(directory ?? process.cwd()) + const allSkills = await Promise.all( + projectSkillDirs.map((skillsDir) => loadSkillsFromDir({ skillsDir, scope: "project" })), + ) + return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat())) } export async function loadOpencodeGlobalSkills(): Promise> { @@ -30,8 +37,28 @@ export async function loadOpencodeGlobalSkills(): Promise> { - const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "skills") - const skills = await loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" }) + const opencodeProjectSkillDirs = findProjectOpencodeSkillDirs( + directory ?? process.cwd(), + ) + const allSkills = await Promise.all( + opencodeProjectSkillDirs.map((skillsDir) => + loadSkillsFromDir({ skillsDir, scope: "opencode-project" }), + ), + ) + return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat())) +} + +export async function loadProjectAgentsSkills(directory?: string): Promise> { + const agentsProjectSkillDirs = findProjectAgentsSkillDirs(directory ?? process.cwd()) + const allSkills = await Promise.all( + agentsProjectSkillDirs.map((skillsDir) => loadSkillsFromDir({ skillsDir, scope: "project" })), + ) + return skillsToCommandDefinitionRecord(deduplicateSkillsByName(allSkills.flat())) +} + +export async function loadGlobalAgentsSkills(): Promise> { + const agentsGlobalDir = join(homedir(), ".agents", "skills") + const skills = await loadSkillsFromDir({ skillsDir: agentsGlobalDir, scope: "user" }) return skillsToCommandDefinitionRecord(skills) } @@ -104,8 +131,11 @@ export async function discoverUserClaudeSkills(): Promise { } export async function discoverProjectClaudeSkills(directory?: string): Promise { - const projectSkillsDir = join(directory ?? process.cwd(), ".claude", "skills") - return loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" }) + const projectSkillDirs = findProjectClaudeSkillDirs(directory ?? process.cwd()) + const allSkills = await Promise.all( + projectSkillDirs.map((skillsDir) => loadSkillsFromDir({ skillsDir, scope: "project" })), + ) + return deduplicateSkillsByName(allSkills.flat()) } export async function discoverOpencodeGlobalSkills(): Promise { @@ -117,13 +147,23 @@ export async function discoverOpencodeGlobalSkills(): Promise { } export async function discoverOpencodeProjectSkills(directory?: string): Promise { - const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "skills") - return loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" }) + const opencodeProjectSkillDirs = findProjectOpencodeSkillDirs( + directory ?? process.cwd(), + ) + const allSkills = await Promise.all( + opencodeProjectSkillDirs.map((skillsDir) => + loadSkillsFromDir({ skillsDir, scope: "opencode-project" }), + ), + ) + return deduplicateSkillsByName(allSkills.flat()) } export async function discoverProjectAgentsSkills(directory?: string): Promise { - const agentsProjectDir = join(directory ?? process.cwd(), ".agents", "skills") - return loadSkillsFromDir({ skillsDir: agentsProjectDir, scope: "project" }) + const agentsProjectSkillDirs = findProjectAgentsSkillDirs(directory ?? process.cwd()) + const allSkills = await Promise.all( + agentsProjectSkillDirs.map((skillsDir) => loadSkillsFromDir({ skillsDir, scope: "project" })), + ) + return deduplicateSkillsByName(allSkills.flat()) } export async function discoverGlobalAgentsSkills(): Promise { diff --git a/src/features/opencode-skill-loader/project-skill-discovery.test.ts b/src/features/opencode-skill-loader/project-skill-discovery.test.ts new file mode 100644 index 000000000..0d34da8ea --- /dev/null +++ b/src/features/opencode-skill-loader/project-skill-discovery.test.ts @@ -0,0 +1,86 @@ +import { execFileSync } from "node:child_process" +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { + discoverOpencodeProjectSkills, + discoverProjectAgentsSkills, + discoverProjectClaudeSkills, +} from "./loader" + +function writeSkill(directory: string, name: string, description: string): void { + mkdirSync(directory, { recursive: true }) + writeFileSync( + join(directory, "SKILL.md"), + `---\nname: ${name}\ndescription: ${description}\n---\nBody\n`, + ) +} + +describe("project skill discovery", () => { + let tempDir = "" + + beforeEach(() => { + tempDir = mkdtempSync(join(tmpdir(), "omo-project-skill-discovery-")) + }) + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }) + }) + + it("discovers ancestor project skill directories up to the worktree root", async () => { + // given + const repositoryDir = join(tempDir, "repo") + const nestedDirectory = join(repositoryDir, "packages", "app", "src") + + mkdirSync(nestedDirectory, { recursive: true }) + execFileSync("git", ["init"], { + cwd: repositoryDir, + stdio: ["ignore", "ignore", "ignore"], + }) + + writeSkill( + join(repositoryDir, ".claude", "skills", "repo-claude"), + "repo-claude", + "Discovered from the repository root", + ) + writeSkill( + join(repositoryDir, ".agents", "skills", "repo-agents"), + "repo-agents", + "Discovered from the repository root", + ) + writeSkill( + join(repositoryDir, ".opencode", "skill", "repo-opencode"), + "repo-opencode", + "Discovered from the repository root", + ) + + writeSkill( + join(tempDir, ".claude", "skills", "outside-claude"), + "outside-claude", + "Should stay outside the worktree", + ) + writeSkill( + join(tempDir, ".agents", "skills", "outside-agents"), + "outside-agents", + "Should stay outside the worktree", + ) + writeSkill( + join(tempDir, ".opencode", "skills", "outside-opencode"), + "outside-opencode", + "Should stay outside the worktree", + ) + + // when + const [claudeSkills, agentSkills, opencodeSkills] = await Promise.all([ + discoverProjectClaudeSkills(nestedDirectory), + discoverProjectAgentsSkills(nestedDirectory), + discoverOpencodeProjectSkills(nestedDirectory), + ]) + + // then + expect(claudeSkills.map(skill => skill.name)).toEqual(["repo-claude"]) + expect(agentSkills.map(skill => skill.name)).toEqual(["repo-agents"]) + expect(opencodeSkills.map(skill => skill.name)).toEqual(["repo-opencode"]) + }) +}) diff --git a/src/generated/model-capabilities.generated.json b/src/generated/model-capabilities.generated.json new file mode 100644 index 000000000..91b952581 --- /dev/null +++ b/src/generated/model-capabilities.generated.json @@ -0,0 +1,40690 @@ +{ + "generatedAt": "2026-03-25T13:44:08.677Z", + "sourceUrl": "https://models.dev/api.json", + "models": { + "nvidia/llama-3.3-70b-instruct-fp8": { + "id": "nvidia/Llama-3.3-70B-Instruct-FP8", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "microsoft/phi-4-multimodal-instruct": { + "id": "microsoft/phi-4-multimodal-instruct", + "family": "phi", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "temperature": true + }, + "intfloat/multilingual-e5-large-instruct": { + "id": "intfloat/multilingual-e5-large-instruct", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + }, + "temperature": false + }, + "moonshotai/kimi-k2.5": { + "id": "moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536, + "input": 256000 + }, + "temperature": true + }, + "kblab/kb-whisper-large": { + "id": "KBLab/kb-whisper-large", + "family": "whisper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 480000, + "output": 4800 + }, + "temperature": false + }, + "qwen/qwen3-30b-a3b-instruct-2507-fp8": { + "id": "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "qwen/qwen3-embedding-8b": { + "id": "Qwen/Qwen3-Embedding-8B", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096, + "input": 32768 + }, + "temperature": false + }, + "qwen/qwen3-vl-30b-a3b-instruct": { + "id": "qwen/qwen3-vl-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "temperature": true + }, + "mistralai/voxtral-small-24b-2507": { + "id": "mistralai/voxtral-small-24b-2507", + "family": "voxtral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 6400 + }, + "temperature": true + }, + "mistralai/devstral-small-2-24b-instruct-2512": { + "id": "mistralai/devstral-small-2-24b-instruct-2512", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mistralai/magistral-small-2509": { + "id": "mistralai/Magistral-Small-2509", + "family": "magistral-small", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "openai/gpt-oss-120b": { + "id": "openai/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "temperature": true + }, + "openai/whisper-large-v3": { + "id": "openai/whisper-large-v3", + "family": "whisper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + }, + "temperature": false + }, + "glm-5": { + "id": "glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 16384 + } + }, + "glm-4.5-air": { + "id": "glm-4.5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "glm-4.5": { + "id": "glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "glm-4.5-flash": { + "id": "glm-4.5-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "glm-4.7-flash": { + "id": "glm-4.7-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "output": 203000 + } + }, + "glm-4.6": { + "id": "glm-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "glm-4.7": { + "id": "glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 198000 + } + }, + "glm-5-turbo": { + "id": "glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "glm-4.5v": { + "id": "glm-4.5v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16384 + } + }, + "glm-4.6v": { + "id": "glm-4.6v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "minimax-m2.5": { + "id": "MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 196601, + "output": 131072 + } + }, + "qwen3-coder-next": { + "id": "qwen3-coder-next", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536, + "input": 262144 + } + }, + "kimi-k2.5": { + "id": "kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen3-max-2026-01-23": { + "id": "qwen3-max-2026-01-23", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768, + "input": 256000 + } + }, + "qwen3.5-plus": { + "id": "qwen3.5-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen3-coder-plus": { + "id": "qwen3-coder-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "xiaomi/mimo-v2-omni": { + "id": "xiaomi/mimo-v2-omni", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + }, + "family": "mimo" + }, + "xiaomi/mimo-v2-flash-free": { + "id": "xiaomi/mimo-v2-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 64000 + } + }, + "xiaomi/mimo-v2-flash": { + "id": "xiaomi/mimo-v2-flash", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768, + "input": 256000 + }, + "family": "mimo" + }, + "xiaomi/mimo-v2-pro": { + "id": "xiaomi/mimo-v2-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + }, + "family": "mimo" + }, + "kuaishou/kat-coder-pro-v1-free": { + "id": "kuaishou/kat-coder-pro-v1-free", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "kuaishou/kat-coder-pro-v1": { + "id": "kuaishou/kat-coder-pro-v1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "stepfun/step-3.5-flash-free": { + "id": "stepfun/step-3.5-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "stepfun/step-3.5-flash": { + "id": "stepfun/step-3.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + }, + "family": "step" + }, + "stepfun/step-3": { + "id": "stepfun/step-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 64000 + } + }, + "inclusionai/ling-1t": { + "id": "inclusionai/ling-1t", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "inclusionai/ring-1t": { + "id": "inclusionai/ring-1t", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "volcengine/doubao-seed-1.8": { + "id": "volcengine/doubao-seed-1.8", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-pro": { + "id": "volcengine/doubao-seed-2.0-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-mini": { + "id": "volcengine/doubao-seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-code": { + "id": "volcengine/doubao-seed-code", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-lite": { + "id": "volcengine/doubao-seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "volcengine/doubao-seed-2.0-code": { + "id": "volcengine/doubao-seed-2.0-code", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "deepseek/deepseek-v3.2": { + "id": "deepseek/deepseek-v3.2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163000, + "output": 65536, + "input": 163000 + }, + "family": "deepseek" + }, + "deepseek/deepseek-chat": { + "id": "deepseek/deepseek-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek/deepseek-v3.2-exp": { + "id": "deepseek/deepseek-v3.2-exp", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + }, + "family": "deepseek" + }, + "moonshotai/kimi-k2-0905": { + "id": "moonshotai/kimi-k2-0905", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + }, + "family": "kimi" + }, + "moonshotai/kimi-k2-thinking": { + "id": "moonshotai/kimi-k2-thinking", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 262144, + "input": 256000 + }, + "family": "kimi-thinking" + }, + "moonshotai/kimi-k2-thinking-turbo": { + "id": "moonshotai/kimi-k2-thinking-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + }, + "family": "kimi-thinking" + }, + "baidu/ernie-5.0-thinking-preview": { + "id": "baidu/ernie-5.0-thinking-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "google/gemini-2.5-flash": { + "id": "google/gemini-2.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65535 + }, + "family": "gemini-flash" + }, + "google/gemini-3.1-flash-lite-preview": { + "id": "google/gemini-3.1-flash-lite-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + }, + "family": "gemini" + }, + "google/gemini-3-flash-preview": { + "id": "google/gemini-3-flash-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + }, + "family": "gemini-flash" + }, + "google/gemini-2.5-flash-lite": { + "id": "google/gemini-2.5-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65535 + }, + "family": "gemini-flash-lite" + }, + "google/gemini-3.1-pro-preview": { + "id": "google/gemini-3.1-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + }, + "family": "gemini" + }, + "google/gemini-3-pro-image-preview": { + "id": "google/gemini-3-pro-image-preview", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/gemini-3-pro-preview": { + "id": "google/gemini-3-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + }, + "family": "gemini-pro" + }, + "google/gemini-2.5-pro": { + "id": "google/gemini-2.5-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + }, + "family": "gemini-pro" + }, + "z-ai/glm-5": { + "id": "z-ai/glm-5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + }, + "family": "glm" + }, + "z-ai/glm-4.7-flashx": { + "id": "z-ai/glm-4.7-flashx", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.5-air": { + "id": "z-ai/glm-4.5-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm-air" + }, + "z-ai/glm-4.5": { + "id": "z-ai/glm-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm" + }, + "z-ai/glm-4.6v-flash-free": { + "id": "z-ai/glm-4.6v-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.6": { + "id": "z-ai/glm-4.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 65535, + "input": 200000 + }, + "family": "glm" + }, + "z-ai/glm-4.7": { + "id": "z-ai/glm-4.7", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + }, + "family": "glm" + }, + "z-ai/glm-4.7-flash-free": { + "id": "z-ai/glm-4.7-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-4.6v-flash": { + "id": "z-ai/glm-4.6v-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "z-ai/glm-5-turbo": { + "id": "z-ai/glm-5-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "z-ai/glm-4.6v": { + "id": "z-ai/glm-4.6v", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "qwen/qwen3.5-flash": { + "id": "qwen/qwen3.5-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1020000, + "output": 1020000 + } + }, + "qwen/qwen3.5-plus": { + "id": "Qwen/Qwen3.5-Plus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + }, + "family": "qwen" + }, + "qwen/qwen3-max": { + "id": "qwen/qwen3-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen3-coder-plus": { + "id": "qwen/qwen3-coder-plus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "x-ai/grok-code-fast-1": { + "id": "x-ai/grok-code-fast-1", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 131072, + "input": 256000 + }, + "family": "grok" + }, + "x-ai/grok-4-fast": { + "id": "x-ai/grok-4-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 131072, + "input": 2000000 + }, + "family": "grok" + }, + "x-ai/grok-4": { + "id": "x-ai/grok-4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 51200 + }, + "family": "grok" + }, + "x-ai/grok-4.1-fast-non-reasoning": { + "id": "x-ai/grok-4.1-fast-non-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "x-ai/grok-4.1-fast": { + "id": "x-ai/grok-4.1-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 131072, + "input": 2000000 + }, + "family": "grok" + }, + "x-ai/grok-4.2-fast": { + "id": "x-ai/grok-4.2-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "x-ai/grok-4.2-fast-non-reasoning": { + "id": "x-ai/grok-4.2-fast-non-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "openai/gpt-5.3-codex": { + "id": "openai/gpt-5.3-codex", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" + }, + "openai/gpt-5-codex": { + "id": "openai/gpt-5-codex", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768, + "input": 256000 + }, + "family": "gpt-codex" + }, + "openai/gpt-5.2-codex": { + "id": "openai/gpt-5.2-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt-codex" + }, + "openai/gpt-5.1": { + "id": "openai/gpt-5.1", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt" + }, + "openai/gpt-5.1-chat": { + "id": "openai/gpt-5.1-chat", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt" + }, + "openai/gpt-5.1-codex-mini": { + "id": "openai/gpt-5.1-codex-mini", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt-codex-mini" + }, + "openai/gpt-5.2": { + "id": "openai/gpt-5.2", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt" + }, + "openai/gpt-5": { + "id": "openai/gpt-5", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt" + }, + "openai/gpt-5.4": { + "id": "openai/gpt-5.4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "output": 128000, + "input": 922000 + }, + "family": "gpt" + }, + "openai/gpt-5.4-pro": { + "id": "openai/gpt-5.4-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "output": 128000, + "input": 922000 + }, + "family": "gpt" + }, + "openai/gpt-5.3-chat": { + "id": "openai/gpt-5.3-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + }, + "family": "gpt" + }, + "openai/gpt-5.1-codex": { + "id": "openai/gpt-5.1-codex", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt-codex" + }, + "openai/gpt-5.2-pro": { + "id": "openai/gpt-5.2-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt-pro" + }, + "openai/gpt-5.4-nano": { + "id": "openai/gpt-5.4-nano", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" + }, + "openai/gpt-5.4-mini": { + "id": "openai/gpt-5.4-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" + }, + "minimax/minimax-m2.5-lightning": { + "id": "minimax/minimax-m2.5-lightning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimax/minimax-m2.1": { + "id": "minimax/minimax-m2.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072, + "input": 200000 + }, + "family": "minimax" + }, + "minimax/minimax-m2.7": { + "id": "minimax/minimax-m2.7", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072, + "input": 204800 + }, + "family": "minimax" + }, + "minimax/minimax-m2.7-highspeed": { + "id": "minimax/minimax-m2.7-highspeed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131100 + }, + "family": "minimax" + }, + "minimax/minimax-m2": { + "id": "minimax/minimax-m2", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + }, + "family": "minimax" + }, + "minimax/minimax-m2.5": { + "id": "MiniMax/MiniMax-M2.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072, + "input": 204800 + }, + "family": "minimax" + }, + "anthropic/claude-3.5-sonnet": { + "id": "anthropic/claude-3.5-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-sonnet" + }, + "anthropic/claude-3.7-sonnet": { + "id": "anthropic/claude-3.7-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "anthropic/claude-opus-4.1": { + "id": "anthropic/claude-opus-4.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + }, + "family": "claude-opus" + }, + "anthropic/claude-sonnet-4.6": { + "id": "anthropic/claude-sonnet-4.6", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000, + "input": 1000000 + }, + "family": "claude-sonnet" + }, + "anthropic/claude-haiku-4.5": { + "id": "anthropic/claude-haiku-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-haiku" + }, + "anthropic/claude-3.5-haiku": { + "id": "anthropic/claude-3.5-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-haiku" + }, + "anthropic/claude-opus-4.5": { + "id": "anthropic/claude-opus-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-opus" + }, + "anthropic/claude-opus-4": { + "id": "anthropic/claude-opus-4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + }, + "family": "claude-opus" + }, + "anthropic/claude-sonnet-4": { + "id": "anthropic/claude-sonnet-4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "anthropic/claude-sonnet-4.5": { + "id": "anthropic/claude-sonnet-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "anthropic/claude-opus-4.6": { + "id": "anthropic/claude-opus-4.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000, + "input": 1000000 + }, + "family": "claude-opus" + }, + "zai-org/glm-4.6": { + "id": "zai-org/GLM-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "deepseek-ai/deepseek-r1-0528": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 163840, + "input": 128000 + } + }, + "intel/qwen3-coder-480b-a35b-instruct-int4-mixed-ar": { + "id": "Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 106000, + "output": 4096 + } + }, + "moonshotai/kimi-k2-instruct-0905": { + "id": "moonshotai/Kimi-K2-Instruct-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144, + "input": 256000 + } + }, + "meta-llama/llama-3.2-90b-vision-instruct": { + "id": "meta-llama/llama-3.2-90b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384, + "input": 131072 + } + }, + "meta-llama/llama-3.3-70b-instruct": { + "id": "meta-llama/llama-3.3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384, + "input": 131072 + } + }, + "meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen3-next-80b-a3b-instruct": { + "id": "Qwen/Qwen3-Next-80B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3-235b-a22b-thinking-2507": { + "id": "Qwen/Qwen3-235B-A22B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen2.5-vl-32b-instruct": { + "id": "Qwen/Qwen2.5-VL-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "mistralai/mistral-nemo-instruct-2407": { + "id": "mistralai/Mistral-Nemo-Instruct-2407", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192, + "input": 16384 + } + }, + "mistralai/magistral-small-2506": { + "id": "mistralai/Magistral-Small-2506", + "family": "magistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-large-instruct-2411": { + "id": "mistralai/Mistral-Large-Instruct-2411", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/devstral-small-2505": { + "id": "mistralai/Devstral-Small-2505", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192, + "input": 32768 + } + }, + "openai/gpt-oss-20b": { + "id": "openai/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072, + "input": 128000 + } + }, + "nvidia/nemotron-3-super-120b-a12b": { + "id": "nvidia/nemotron-3-super-120b-a12b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144, + "input": 256000 + } + }, + "nvidia/llama-3.1-nemotron-70b-instruct": { + "id": "nvidia/llama-3.1-nemotron-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "nvidia/llama-3.1-nemotron-ultra-253b-v1": { + "id": "nvidia/Llama-3.1-Nemotron-Ultra-253B-v1", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "nvidia/llama-3.1-nemotron-51b-instruct": { + "id": "nvidia/llama-3.1-nemotron-51b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/parakeet-tdt-0.6b-v2": { + "id": "nvidia/parakeet-tdt-0.6b-v2", + "family": "parakeet", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "nvidia/nvidia-nemotron-nano-9b-v2": { + "id": "nvidia/nvidia-nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "nvidia/llama-embed-nemotron-8b": { + "id": "nvidia/llama-embed-nemotron-8b", + "family": "llama", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1.5": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1": { + "id": "nvidia/Llama-3.3-Nemotron-Super-49B-v1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "family": "nemotron" + }, + "nvidia/llama3-chatqa-1.5-70b": { + "id": "nvidia/llama3-chatqa-1.5-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/cosmos-nemotron-34b": { + "id": "nvidia/cosmos-nemotron-34b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "nvidia/nemoretriever-ocr-v1": { + "id": "nvidia/nemoretriever-ocr-v1", + "family": "nemoretriever", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "nvidia/nemotron-4-340b-instruct": { + "id": "nvidia/nemotron-4-340b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemotron-3-nano-30b-a3b": { + "id": "nvidia/nemotron-3-nano-30b-a3b", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 262144, + "input": 256000 + } + }, + "microsoft/phi-3-small-128k-instruct": { + "id": "microsoft/phi-3-small-128k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-medium-128k-instruct": { + "id": "microsoft/phi-3-medium-128k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3.5-moe-instruct": { + "id": "microsoft/phi-3.5-moe-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-vision-128k-instruct": { + "id": "microsoft/phi-3-vision-128k-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-4-mini-instruct": { + "id": "microsoft/phi-4-mini-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3.5-vision-instruct": { + "id": "microsoft/phi-3.5-vision-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + }, + "family": "phi" + }, + "microsoft/phi-3-medium-4k-instruct": { + "id": "microsoft/phi-3-medium-4k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + }, + "family": "phi" + }, + "microsoft/phi-3-small-8k-instruct": { + "id": "microsoft/phi-3-small-8k-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + }, + "family": "phi" + }, + "minimaxai/minimax-m2.1": { + "id": "MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608, + "input": 120000 + } + }, + "minimaxai/minimax-m2.5": { + "id": "MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + } + }, + "deepseek-ai/deepseek-v3.1": { + "id": "deepseek-ai/DeepSeek-V3.1", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536, + "input": 128000 + } + }, + "deepseek-ai/deepseek-r1": { + "id": "deepseek-ai/DeepSeek-R1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + }, + "family": "deepseek-thinking" + }, + "deepseek-ai/deepseek-v3.1-terminus": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536, + "input": 128000 + } + }, + "deepseek-ai/deepseek-coder-6.7b-instruct": { + "id": "deepseek-ai/deepseek-coder-6.7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "deepseek-ai/deepseek-v3.2": { + "id": "deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536, + "input": 160000 + } + }, + "moonshotai/kimi-k2-instruct": { + "id": "moonshotai/kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192, + "input": 256000 + } + }, + "google/codegemma-7b": { + "id": "google/codegemma-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-2-2b-it": { + "id": "google/gemma-2-2b-it", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096, + "input": 8000 + } + }, + "google/gemma-3-1b-it": { + "id": "google/gemma-3-1b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-2-27b-it": { + "id": "google/gemma-2-27b-it", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "google/gemma-3n-e2b-it": { + "id": "google/gemma-3n-e2b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/codegemma-1.1-7b": { + "id": "google/codegemma-1.1-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemma-3n-e4b-it": { + "id": "google/gemma-3n-e4b-it", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554 + }, + "family": "gemma" + }, + "google/gemma-3-12b-it": { + "id": "google/gemma-3-12b-it", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "gemma" + }, + "google/gemma-3-27b-it": { + "id": "google/gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536, + "input": 100000 + } + }, + "z-ai/glm4.7": { + "id": "z-ai/glm4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "z-ai/glm5": { + "id": "z-ai/glm5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131000 + } + }, + "stepfun-ai/step-3.5-flash": { + "id": "stepfun-ai/step-3.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000, + "input": 256000 + }, + "family": "step" + }, + "qwen/qwen3-next-80b-a3b-thinking": { + "id": "qwen/qwen3-next-80b-a3b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768, + "input": 120000 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "qwen/qwq-32b": { + "id": "qwen/qwq-32b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen2.5-coder-7b-instruct": { + "id": "qwen/qwen2.5-coder-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554 + } + }, + "qwen/qwen3.5-397b-a17b": { + "id": "qwen/qwen3.5-397b-a17b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 258048, + "output": 65536, + "input": 258048 + } + }, + "qwen/qwen2.5-coder-32b-instruct": { + "id": "Qwen/Qwen2.5-Coder-32B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen3-235b-a22b": { + "id": "Qwen/Qwen3-235B-A22B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "meta/llama-3.1-70b-instruct": { + "id": "meta/llama-3.1-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.3-70b-instruct": { + "id": "meta/llama-3.3-70b-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + }, + "family": "llama" + }, + "meta/llama-4-scout-17b-16e-instruct": { + "id": "meta/llama-4-scout-17b-16e-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "llama" + }, + "meta/llama-3.2-11b-vision-instruct": { + "id": "meta/llama-3.2-11b-vision-instruct", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "llama" + }, + "meta/llama3-8b-instruct": { + "id": "meta/llama3-8b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/codellama-70b": { + "id": "meta/codellama-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.2-1b-instruct": { + "id": "meta/llama-3.2-1b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + }, + "family": "llama" + }, + "meta/llama-3.1-405b-instruct": { + "id": "meta/llama-3.1-405b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama3-70b-instruct": { + "id": "meta/llama3-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-4-maverick-17b-128e-instruct": { + "id": "meta/llama-4-maverick-17b-128e-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-large-3-675b-instruct-2512": { + "id": "mistralai/mistral-large-3-675b-instruct-2512", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 256000, + "input": 262144 + } + }, + "mistralai/mamba-codestral-7b-v0.1": { + "id": "mistralai/mamba-codestral-7b-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/codestral-22b-instruct-v0.1": { + "id": "mistralai/codestral-22b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/mistral-large-2-instruct": { + "id": "mistralai/mistral-large-2-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/ministral-14b-instruct-2512": { + "id": "mistralai/ministral-14b-instruct-2512", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768, + "input": 262144 + } + }, + "mistralai/mistral-small-3.1-24b-instruct-2503": { + "id": "mistralai/mistral-small-3.1-24b-instruct-2503", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistralai/devstral-2-123b-instruct-2512": { + "id": "mistralai/devstral-2-123b-instruct-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536, + "input": 262144 + } + }, + "black-forest-labs/flux.1-dev": { + "id": "black-forest-labs/flux.1-dev", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 4096, + "output": 0 + } + }, + "deepseek-ai/deepseek-r1-distill-llama-70b": { + "id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "moonshotai/kimi-k2": { + "id": "moonshotai/kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 26215 + } + }, + "qwen/qwen3-coder": { + "id": "qwen/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 52429 + } + }, + "openai/gpt-4.1": { + "id": "openai/gpt-4.1", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768, + "input": 1047576 + } + }, + "openai/gpt-5-mini": { + "id": "openai/gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + } + }, + "openai/gpt-5-nano": { + "id": "openai/gpt-5-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + } + }, + "kimi-k2": { + "id": "kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen3-max-preview": { + "id": "qwen3-max-preview", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "deepseek-v3": { + "id": "deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "kimi-k2-0905": { + "id": "kimi-k2-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "qwen3-235b-a22b-instruct": { + "id": "qwen3-235b-a22b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "deepseek-r1": { + "id": "deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384, + "input": 128000 + } + }, + "qwen3-32b": { + "id": "qwen3-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "deepseek-v3.2": { + "id": "deepseek-v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "qwen3-235b": { + "id": "qwen3-235b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "qwen3-vl-plus": { + "id": "qwen3-vl-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen3-235b-a22b-thinking-2507": { + "id": "qwen3-235b-a22b-thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-max": { + "id": "qwen3-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-30b-a3b-instruct-2507": { + "id": "Qwen/Qwen3-30B-A3B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144, + "input": 120000 + } + }, + "qwen/qwen3-30b-a3b-thinking-2507": { + "id": "qwen/qwen3-30b-a3b-thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554, + "input": 120000 + } + }, + "qwen/qwen3-coder-30b-a3b-instruct": { + "id": "qwen/qwen3-coder-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 32768, + "input": 120000 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "zhipuai/glm-4.6": { + "id": "ZhipuAI/GLM-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 98304 + } + }, + "zhipuai/glm-4.5": { + "id": "ZhipuAI/GLM-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "cerebras-llama-4-maverick-17b-128e-instruct": { + "id": "cerebras-llama-4-maverick-17b-128e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-4-scout-17b-16e-instruct-fp8": { + "id": "llama-4-scout-17b-16e-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-3.3-8b-instruct": { + "id": "llama-3.3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "groq-llama-4-maverick-17b-128e-instruct": { + "id": "groq-llama-4-maverick-17b-128e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-3.3-70b-instruct": { + "id": "llama-3.3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "cerebras-llama-4-scout-17b-16e-instruct": { + "id": "cerebras-llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "llama-4-maverick-17b-128e-instruct-fp8": { + "id": "llama-4-maverick-17b-128e-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral/mistral-nemo-12b-instruct": { + "id": "mistral/mistral-nemo-12b-instruct", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "google/gemma-3": { + "id": "google/gemma-3", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 125000, + "output": 4096 + } + }, + "qwen/qwen3-embedding-4b": { + "id": "Qwen/Qwen3-Embedding-4B", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 2048 + } + }, + "qwen/qwen-2.5-7b-vision-instruct": { + "id": "qwen/qwen-2.5-7b-vision-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 125000, + "output": 4096 + } + }, + "meta/llama-3.2-3b-instruct": { + "id": "meta/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "meta/llama-3.1-8b-instruct": { + "id": "meta/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + } + }, + "osmosis/osmosis-structure-0.6b": { + "id": "osmosis/osmosis-structure-0.6b", + "family": "osmosis", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4000, + "output": 2048 + } + }, + "zai-org/glm-4.7-flash": { + "id": "zai-org/GLM-4.7-Flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535, + "input": 200000 + } + }, + "zai-org/glm-4.7": { + "id": "zai-org/glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000, + "input": 200000 + } + }, + "zai-org/glm-4.6v": { + "id": "zai-org/GLM-4.6V", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "zai-org/glm-4.5": { + "id": "zai-org/glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304, + "input": 124000 + } + }, + "zai-org/glm-5": { + "id": "zai-org/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000, + "input": 200000 + } + }, + "minimaxai/minimax-m2": { + "id": "MiniMaxAI/MiniMax-M2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "meta-llama/llama-3.1-8b-instruct-turbo": { + "id": "meta-llama/Llama-3.1-8B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta-llama/llama-3.1-70b-instruct-turbo": { + "id": "meta-llama/Llama-3.1-70B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta-llama/llama-4-scout-17b-16e-instruct": { + "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct", + "family": "llama", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + }, + "temperature": true + }, + "meta-llama/llama-3.1-70b-instruct": { + "id": "meta-llama/llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + }, + "temperature": true + }, + "meta-llama/llama-3.1-8b-instruct": { + "id": "meta-llama/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384, + "input": 131072 + }, + "temperature": true + }, + "meta-llama/llama-3.3-70b-instruct-turbo": { + "id": "meta-llama/Llama-3.3-70B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "temperature": true + }, + "qwen/qwen3-coder-480b-a35b-instruct-turbo": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "anthropic/claude-3-7-sonnet-latest": { + "id": "anthropic/claude-3-7-sonnet-latest", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-4-opus": { + "id": "anthropic/claude-4-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "perplexity/sonar": { + "id": "perplexity/sonar", + "family": "sonar", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127072, + "output": 25415 + } + }, + "anthropic/claude-opus-4-6": { + "id": "anthropic/claude-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-sonnet-4-6": { + "id": "anthropic/claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-haiku-4-5": { + "id": "anthropic/claude-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 62000 + } + }, + "anthropic/claude-opus-4-5": { + "id": "anthropic/claude-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic/claude-sonnet-4-5": { + "id": "anthropic/claude-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "xai/grok-4-1-fast-non-reasoning": { + "id": "xai/grok-4-1-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "mimo-v2-omni": { + "id": "mimo-v2-omni", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "mimo-v2-flash": { + "id": "mimo-v2-flash", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mimo-v2-pro": { + "id": "mimo-v2-pro", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "hf:minimaxai/minimax-m2.5": { + "id": "hf:MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 191488, + "output": 65536 + } + }, + "hf:minimaxai/minimax-m2": { + "id": "hf:MiniMaxAI/MiniMax-M2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 131000 + } + }, + "hf:minimaxai/minimax-m2.1": { + "id": "hf:MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "hf:deepseek-ai/deepseek-r1": { + "id": "hf:deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-r1-0528": { + "id": "hf:deepseek-ai/DeepSeek-R1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3.1": { + "id": "hf:deepseek-ai/DeepSeek-V3.1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3.2": { + "id": "hf:deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 162816, + "input": 162816, + "output": 8000 + } + }, + "hf:deepseek-ai/deepseek-v3-0324": { + "id": "hf:deepseek-ai/DeepSeek-V3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3": { + "id": "hf:deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:deepseek-ai/deepseek-v3.1-terminus": { + "id": "hf:deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "hf:moonshotai/kimi-k2-instruct-0905": { + "id": "hf:moonshotai/Kimi-K2-Instruct-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "hf:moonshotai/kimi-k2.5": { + "id": "hf:moonshotai/Kimi-K2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:moonshotai/kimi-k2-thinking": { + "id": "hf:moonshotai/Kimi-K2-Thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "hf:openai/gpt-oss-120b": { + "id": "hf:openai/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:nvidia/kimi-k2.5-nvfp4": { + "id": "hf:nvidia/Kimi-K2.5-NVFP4", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "hf:meta-llama/llama-4-scout-17b-16e-instruct": { + "id": "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 328000, + "output": 4096 + } + }, + "hf:meta-llama/llama-3.1-405b-instruct": { + "id": "hf:meta-llama/Llama-3.1-405B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-3.1-70b-instruct": { + "id": "hf:meta-llama/Llama-3.1-70B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-3.1-8b-instruct": { + "id": "hf:meta-llama/Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-3.3-70b-instruct": { + "id": "hf:meta-llama/Llama-3.3-70B-Instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "hf:meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "hf:meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 524000, + "output": 4096 + } + }, + "hf:zai-org/glm-4.7-flash": { + "id": "hf:zai-org/GLM-4.7-Flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "hf:zai-org/glm-4.6": { + "id": "hf:zai-org/GLM-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "hf:zai-org/glm-4.7": { + "id": "hf:zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "hf:qwen/qwen3-235b-a22b-thinking-2507": { + "id": "hf:Qwen/Qwen3-235B-A22B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "hf:qwen/qwen2.5-coder-32b-instruct": { + "id": "hf:Qwen/Qwen2.5-Coder-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "hf:qwen/qwen3-coder-480b-a35b-instruct": { + "id": "hf:Qwen/Qwen3-Coder-480B-A35B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "hf:qwen/qwen3-235b-a22b-instruct-2507": { + "id": "hf:Qwen/Qwen3-235B-A22B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "zai-org/glm-4.7-fp8": { + "id": "zai-org/GLM-4.7-FP8", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "input": 124000, + "output": 65535 + } + }, + "zai-org/glm-4.5-air": { + "id": "zai-org/GLM-4.5-Air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 124000, + "output": 131072 + }, + "family": "glm" + }, + "nvidia/llama-3_1-nemotron-ultra-253b-v1": { + "id": "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + } + }, + "nvidia/nemotron-nano-v2-12b": { + "id": "nvidia/Nemotron-Nano-V2-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 30000, + "output": 4096 + } + }, + "nvidia/nvidia-nemotron-3-nano-30b-a3b": { + "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 30000, + "output": 4096 + } + }, + "nousresearch/hermes-4-405b": { + "id": "nousresearch/hermes-4-405b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 120000, + "output": 26215 + }, + "family": "hermes" + }, + "nousresearch/hermes-4-70b": { + "id": "NousResearch/Hermes-4-70B", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 120000, + "output": 131072 + }, + "family": "nousresearch" + }, + "baai/bge-en-icl": { + "id": "BAAI/bge-en-icl", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 0 + } + }, + "baai/bge-multilingual-gemma2": { + "id": "BAAI/bge-multilingual-gemma2", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 0 + } + }, + "primeintellect/intellect-3": { + "id": "PrimeIntellect/INTELLECT-3", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "deepseek-ai/deepseek-v3-0324-fast": { + "id": "deepseek-ai/DeepSeek-V3-0324-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "deepseek-ai/deepseek-v3-0324": { + "id": "deepseek-ai/DeepSeek-V3-0324", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 120000, + "output": 163840 + }, + "family": "deepseek" + }, + "deepseek-ai/deepseek-r1-0528-fast": { + "id": "deepseek-ai/DeepSeek-R1-0528-fast", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "intfloat/e5-mistral-7b-instruct": { + "id": "intfloat/e5-mistral-7b-instruct", + "family": "mistral", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 32768, + "output": 4096 + } + }, + "moonshotai/kimi-k2.5-fast": { + "id": "moonshotai/Kimi-K2.5-fast", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 8192 + } + }, + "google/gemma-3-27b-it-fast": { + "id": "google/gemma-3-27b-it-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 110000, + "input": 100000, + "output": 8192 + } + }, + "google/gemma-2-9b-it-fast": { + "id": "google/gemma-2-9b-it-fast", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8000, + "output": 4096 + } + }, + "meta-llama/meta-llama-3.1-8b-instruct": { + "id": "meta-llama/Meta-Llama-3.1-8B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 120000, + "output": 4000 + }, + "family": "llama" + }, + "meta-llama/llama-guard-3-8b": { + "id": "meta-llama/llama-guard-3-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 8000, + "output": 26215 + } + }, + "meta-llama/llama-3.3-70b-instruct-fast": { + "id": "meta-llama/Llama-3.3-70B-Instruct-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "meta-llama/meta-llama-3.1-8b-instruct-fast": { + "id": "meta-llama/Meta-Llama-3.1-8B-Instruct-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + } + }, + "qwen/qwen3-32b": { + "id": "Qwen/Qwen3-32B", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "input": 120000, + "output": 40960 + }, + "family": "qwen" + }, + "qwen/qwen2.5-vl-72b-instruct": { + "id": "qwen/qwen2.5-vl-72b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 120000, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen3-32b-fast": { + "id": "Qwen/Qwen3-32B-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "qwen/qwen2.5-coder-7b-fast": { + "id": "Qwen/Qwen2.5-Coder-7B-fast", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + } + }, + "black-forest-labs/flux-dev": { + "id": "black-forest-labs/flux-dev", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 77, + "input": 77, + "output": 0 + } + }, + "black-forest-labs/flux-schnell": { + "id": "black-forest-labs/flux-schnell", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 77, + "input": 77, + "output": 0 + } + }, + "claude-4.5-haiku": { + "id": "claude-4.5-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-haiku" + }, + "claude-3.5-sonnet": { + "id": "claude-3.5-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8200 + } + }, + "qwen3-235b-a22b-instruct-2507": { + "id": "qwen3-235b-a22b-instruct-2507", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + }, + "family": "qwen" + }, + "claude-3.7-sonnet": { + "id": "claude-3.7-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "qwen3-next-80b-a3b-thinking": { + "id": "qwen3-next-80b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "claude-4.0-sonnet": { + "id": "claude-4.0-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen-vl-max-2025-01-25": { + "id": "qwen-vl-max-2025-01-25", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "doubao-seed-1.6-thinking": { + "id": "doubao-seed-1.6-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "qwen3-coder-480b-a35b-instruct": { + "id": "qwen3-coder-480b-a35b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + }, + "family": "qwen" + }, + "claude-4.5-sonnet": { + "id": "claude-4.5-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-sonnet" + }, + "qwen2.5-vl-7b-instruct": { + "id": "qwen2.5-vl-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "doubao-seed-2.0-pro": { + "id": "doubao-seed-2.0-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "gemini-2.5-flash": { + "id": "gemini-2.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + }, + "family": "gemini-flash" + }, + "deepseek-v3.1": { + "id": "deepseek-v3.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "deepseek" + }, + "doubao-seed-1.6": { + "id": "doubao-seed-1.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "doubao-seed-2.0-mini": { + "id": "doubao-seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "claude-4.0-opus": { + "id": "claude-4.0-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "qwen-turbo": { + "id": "qwen-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384, + "input": 1000000 + }, + "family": "qwen" + }, + "gemini-3.0-pro-preview": { + "id": "gemini-3.0-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "deepseek-r1-0528": { + "id": "deepseek-r1-0528", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + }, + "family": "deepseek-thinking" + }, + "doubao-1.5-vision-pro": { + "id": "doubao-1.5-vision-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "gemini-3.0-pro-image-preview": { + "id": "gemini-3.0-pro-image-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen3.5-397b-a17b": { + "id": "qwen3.5-397b-a17b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + }, + "family": "qwen" + }, + "gemini-2.5-flash-lite": { + "id": "gemini-2.5-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + }, + "family": "gemini-flash-lite" + }, + "claude-3.5-haiku": { + "id": "claude-3.5-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + }, + "family": "claude-haiku" + }, + "gpt-oss-120b": { + "id": "gpt-oss-120b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + }, + "family": "gpt-oss" + }, + "deepseek-v3-0324": { + "id": "deepseek-v3-0324", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000, + "input": 128000 + }, + "family": "deepseek" + }, + "doubao-1.5-pro-32k": { + "id": "doubao-1.5-pro-32k", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192, + "input": 32000 + } + }, + "qwen3-30b-a3b-instruct-2507": { + "id": "qwen3-30b-a3b-instruct-2507", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768, + "input": 256000 + } + }, + "qwen2.5-vl-72b-instruct": { + "id": "qwen2.5-vl-72b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen3-235b-a22b": { + "id": "qwen3-235b-a22b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + }, + "family": "qwen" + }, + "doubao-seed-2.0-lite": { + "id": "doubao-seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "claude-4.1-opus": { + "id": "claude-4.1-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "doubao-1.5-thinking-pro": { + "id": "doubao-1.5-thinking-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "gemini-2.5-flash-image": { + "id": "gemini-2.5-flash-image", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + }, + "family": "gemini-flash" + }, + "minimax-m1": { + "id": "MiniMax-M1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 131072, + "input": 1000000 + }, + "family": "minimax" + }, + "doubao-seed-1.6-flash": { + "id": "doubao-seed-1.6-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "qwen3-vl-30b-a3b-thinking": { + "id": "qwen3-vl-30b-a3b-thinking", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "doubao-seed-2.0-code": { + "id": "doubao-seed-2.0-code", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "qwen3-30b-a3b-thinking-2507": { + "id": "qwen3-30b-a3b-thinking-2507", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 126000, + "output": 32000 + } + }, + "claude-4.5-opus": { + "id": "claude-4.5-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + }, + "family": "claude-opus" + }, + "gemini-2.0-flash-lite": { + "id": "gemini-2.0-flash-lite", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192, + "input": 1000000 + }, + "family": "gemini-flash-lite" + }, + "qwen3-next-80b-a3b-instruct": { + "id": "qwen3-next-80b-a3b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "gemini-3.0-flash-preview": { + "id": "gemini-3.0-flash-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "qwen3-30b-a3b": { + "id": "qwen3-30b-a3b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 41000, + "output": 41000 + }, + "family": "qwen" + }, + "gpt-oss-20b": { + "id": "gpt-oss-20b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "gpt-oss" + }, + "kling-v2-6": { + "id": "kling-v2-6", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 99999999, + "output": 99999999 + } + }, + "gemini-2.5-pro": { + "id": "gemini-2.5-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65535, + "input": 1048756 + }, + "family": "gemini-pro" + }, + "gemini-2.0-flash": { + "id": "gemini-2.0-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + }, + "family": "gemini-flash" + }, + "qwen-max-2025-01-25": { + "id": "qwen-max-2025-01-25", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "deepseek/deepseek-v3.2-exp-thinking": { + "id": "deepseek/deepseek-v3.2-exp-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-v3.1-terminus": { + "id": "deepseek/deepseek-v3.1-terminus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + }, + "family": "deepseek" + }, + "deepseek/deepseek-v3.2-251201": { + "id": "deepseek/deepseek-v3.2-251201", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-math-v2": { + "id": "deepseek/deepseek-math-v2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 160000 + } + }, + "deepseek/deepseek-v3.1-terminus-thinking": { + "id": "deepseek/deepseek-v3.1-terminus-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "z-ai/autoglm-phone-9b": { + "id": "z-ai/autoglm-phone-9b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 12800, + "output": 4096 + } + }, + "stepfun-ai/gelab-zero-4b-preview": { + "id": "stepfun-ai/gelab-zero-4b-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "meituan/longcat-flash-lite": { + "id": "meituan/longcat-flash-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 320000 + } + }, + "meituan/longcat-flash-chat": { + "id": "meituan/longcat-flash-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "longcat" + }, + "x-ai/grok-4-fast-reasoning": { + "id": "x-ai/grok-4-fast-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "x-ai/grok-4.1-fast-reasoning": { + "id": "x-ai/grok-4.1-fast-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 131072, + "input": 2000000 + }, + "family": "grok" + }, + "x-ai/grok-4-fast-non-reasoning": { + "id": "x-ai/grok-4-fast-non-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "minimax/minimax-m2.5-highspeed": { + "id": "minimax/minimax-m2.5-highspeed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + }, + "family": "minimax" + }, + "qwen3-coder:480b": { + "id": "qwen3-coder:480b", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "nemotron-3-nano:30b": { + "id": "nemotron-3-nano:30b", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 131072 + } + }, + "ministral-3:8b": { + "id": "ministral-3:8b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "gpt-oss:120b": { + "id": "gpt-oss:120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "devstral-2:123b": { + "id": "devstral-2:123b", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen3-vl:235b-instruct": { + "id": "qwen3-vl:235b-instruct", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "gemini-3-flash-preview": { + "id": "gemini-3-flash-preview", + "family": "gemini-flash", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + }, + "temperature": true + }, + "minimax-m2.1": { + "id": "minimax-m2.1", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196000, + "output": 196000 + }, + "temperature": true + }, + "ministral-3:14b": { + "id": "ministral-3:14b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "qwen3-next:80b": { + "id": "qwen3-next:80b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "kimi-k2:1t": { + "id": "kimi-k2:1t", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "gemma3:12b": { + "id": "gemma3:12b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "minimax-m2.7": { + "id": "MiniMax-M2.7", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + }, + "temperature": true + }, + "gpt-oss:20b": { + "id": "gpt-oss:20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "kimi-k2-thinking": { + "id": "kimi-k2-thinking", + "family": "kimi", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + }, + "temperature": true + }, + "ministral-3:3b": { + "id": "ministral-3:3b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "qwen3.5:397b": { + "id": "qwen3.5:397b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 81920 + } + }, + "gemma3:27b": { + "id": "gemma3:27b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "minimax-m2": { + "id": "minimax-m2", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 400000, + "input": 200000 + }, + "temperature": true + }, + "devstral-small-2:24b": { + "id": "devstral-small-2:24b", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "nemotron-3-super": { + "id": "nemotron-3-super", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "cogito-2.1:671b": { + "id": "cogito-2.1:671b", + "family": "cogito", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32000 + } + }, + "gemma3:4b": { + "id": "gemma3:4b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "deepseek-v3.1:671b": { + "id": "deepseek-v3.1:671b", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "mistral-large-3:675b": { + "id": "mistral-large-3:675b", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "rnj-1:8b": { + "id": "rnj-1:8b", + "family": "rnj", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "qwen3-vl:235b": { + "id": "qwen3-vl:235b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "voxtral-small-24b-2507": { + "id": "voxtral-small-24b-2507", + "family": "voxtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 16384 + } + }, + "mistral-small-3.2-24b-instruct-2506": { + "id": "mistral-small-3.2-24b-instruct-2506", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "qwen3-embedding-8b": { + "id": "qwen3-embedding-8b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "bge-multilingual-gemma2": { + "id": "bge-multilingual-gemma2", + "family": "gemma", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 3072 + } + }, + "deepseek-r1-distill-llama-70b": { + "id": "deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "qwen3-coder-30b-a3b-instruct": { + "id": "qwen3-coder-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536, + "input": 128000 + } + }, + "whisper-large-v3": { + "id": "whisper-large-v3", + "family": "whisper", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 4096 + } + }, + "llama-3.1-8b-instruct": { + "id": "llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "devstral-2-123b-instruct-2512": { + "id": "devstral-2-123b-instruct-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "pixtral-12b-2409": { + "id": "pixtral-12b-2409", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral-nemo-instruct-2407": { + "id": "mistral-nemo-instruct-2407", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "gemma-3-27b-it": { + "id": "Gemma-3-27B-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384, + "input": 32768 + } + }, + "workers-ai/@cf/zai-org/glm-4.7-flash": { + "id": "workers-ai/@cf/zai-org/glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "workers-ai/@cf/nvidia/nemotron-3-120b-a12b": { + "id": "workers-ai/@cf/nvidia/nemotron-3-120b-a12b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "workers-ai/@cf/ibm-granite/granite-4.0-h-micro": { + "id": "workers-ai/@cf/ibm-granite/granite-4.0-h-micro", + "family": "granite", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-small-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-small-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-large-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-large-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-reranker-base": { + "id": "workers-ai/@cf/baai/bge-reranker-base", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-m3": { + "id": "workers-ai/@cf/baai/bge-m3", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/baai/bge-base-en-v1.5": { + "id": "workers-ai/@cf/baai/bge-base-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/pfnet/plamo-embedding-1b": { + "id": "workers-ai/@cf/pfnet/plamo-embedding-1b", + "family": "plamo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { + "id": "workers-ai/@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/facebook/bart-large-cnn": { + "id": "workers-ai/@cf/facebook/bart-large-cnn", + "family": "bart", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1": { + "id": "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/myshell-ai/melotts": { + "id": "workers-ai/@cf/myshell-ai/melotts", + "family": "melotts", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/pipecat-ai/smart-turn-v2": { + "id": "workers-ai/@cf/pipecat-ai/smart-turn-v2", + "family": "smart-turn", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/moonshotai/kimi-k2.5": { + "id": "workers-ai/@cf/moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "workers-ai/@cf/google/gemma-3-12b-it": { + "id": "workers-ai/@cf/google/gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwq-32b": { + "id": "workers-ai/@cf/qwen/qwq-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8": { + "id": "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct": { + "id": "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/qwen/qwen3-embedding-0.6b": { + "id": "workers-ai/@cf/qwen/qwen3-embedding-0.6b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3-8b-instruct-awq": { + "id": "workers-ai/@cf/meta/llama-3-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct": { + "id": "workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-3b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-guard-3-8b": { + "id": "workers-ai/@cf/meta/llama-guard-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.2-1b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.2-1b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast": { + "id": "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3.1-8b-instruct": { + "id": "workers-ai/@cf/meta/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/m2m100-1.2b": { + "id": "workers-ai/@cf/meta/m2m100-1.2b", + "family": "m2m", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-2-7b-chat-fp16": { + "id": "workers-ai/@cf/meta/llama-2-7b-chat-fp16", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/meta/llama-3-8b-instruct": { + "id": "workers-ai/@cf/meta/llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct": { + "id": "workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/aura-2-es": { + "id": "workers-ai/@cf/deepgram/aura-2-es", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/nova-3": { + "id": "workers-ai/@cf/deepgram/nova-3", + "family": "nova", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/deepgram/aura-2-en": { + "id": "workers-ai/@cf/deepgram/aura-2-en", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/openai/gpt-oss-120b": { + "id": "workers-ai/@cf/openai/gpt-oss-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/openai/gpt-oss-20b": { + "id": "workers-ai/@cf/openai/gpt-oss-20b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1b": { + "id": "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1B", + "family": "indictrans", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/huggingface/distilbert-sst-2-int8": { + "id": "workers-ai/@cf/huggingface/distilbert-sst-2-int8", + "family": "distilbert", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it": { + "id": "workers-ai/@cf/aisingapore/gemma-sea-lion-v4-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4o-mini": { + "id": "openai/gpt-4o-mini", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "openai/o1": { + "id": "openai/o1", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/o3": { + "id": "openai/o3", + "family": "o", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/gpt-3.5-turbo": { + "id": "openai/gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 4096, + "input": 16385 + } + }, + "openai/o3-pro": { + "id": "openai/o3-pro", + "family": "o-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 100000 + } + }, + "openai/gpt-4-turbo": { + "id": "openai/gpt-4-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096, + "input": 128000 + } + }, + "openai/o4-mini": { + "id": "openai/o4-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/o3-mini": { + "id": "openai/o3-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/gpt-4": { + "id": "openai/gpt-4", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 4096 + } + }, + "openai/gpt-4o": { + "id": "openai/gpt-4o", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "anthropic/claude-opus-4-1": { + "id": "anthropic/claude-opus-4-1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "anthropic/claude-3-sonnet": { + "id": "anthropic/claude-3-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic/claude-3-5-haiku": { + "id": "anthropic/claude-3-5-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic/claude-3-haiku": { + "id": "anthropic/claude-3-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic/claude-3-opus": { + "id": "anthropic/claude-3-opus", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "solar-pro2": { + "id": "solar-pro2", + "family": "solar-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "solar-mini": { + "id": "solar-mini", + "family": "solar-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "solar-pro3": { + "id": "solar-pro3", + "family": "solar-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "mercury-2": { + "id": "mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 50000 + } + }, + "mercury": { + "id": "mercury", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mercury-edit": { + "id": "mercury-edit", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mercury-coder": { + "id": "mercury-coder", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "zai-org/glm-4.5-fp8": { + "id": "zai-org/GLM-4.5-FP8", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct-fp8": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "minimax-m2.7-highspeed": { + "id": "MiniMax-M2.7-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimax-m2.5-highspeed": { + "id": "MiniMax-M2.5-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "zai-org/autoglm-phone-9b-multilingual": { + "id": "zai-org/autoglm-phone-9b-multilingual", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "zai-org/glm-4.5v": { + "id": "zai-org/glm-4.5v", + "family": "glmv", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 16384 + } + }, + "microsoft/wizardlm-2-8x22b": { + "id": "microsoft/wizardlm-2-8x22b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192, + "input": 65536 + }, + "family": "gpt" + }, + "minimaxai/minimax-m1-80k": { + "id": "MiniMaxAI/MiniMax-M1-80k", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 131072, + "input": 1000000 + } + }, + "skywork/r1v4-lite": { + "id": "skywork/r1v4-lite", + "family": "skywork", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "gryphe/mythomax-l2-13b": { + "id": "Gryphe/MythoMax-L2-13b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4000, + "output": 4096, + "input": 4000 + }, + "family": "llama" + }, + "paddlepaddle/paddleocr-vl": { + "id": "PaddlePaddle/PaddleOCR-VL", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "baichuan/baichuan-m2-32b": { + "id": "baichuan/baichuan-m2-32b", + "family": "baichuan", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "kwaipilot/kat-coder-pro": { + "id": "kwaipilot/kat-coder-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "kwaipilot/kat-coder": { + "id": "kwaipilot/kat-coder", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "deepseek/deepseek-v3-turbo": { + "id": "deepseek/deepseek-v3-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "deepseek/deepseek-prover-v2-671b": { + "id": "deepseek/deepseek-prover-v2-671b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 16384, + "input": 160000 + }, + "family": "deepseek" + }, + "deepseek/deepseek-r1-turbo": { + "id": "deepseek/deepseek-r1-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "deepseek/deepseek-ocr-2": { + "id": "deepseek/deepseek-ocr-2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "deepseek/deepseek-v3.1": { + "id": "deepseek/deepseek-v3.1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + } + }, + "deepseek/deepseek-r1-0528": { + "id": "deepseek/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek/deepseek-r1-0528-qwen3-8b": { + "id": "deepseek/deepseek-r1-0528-qwen3-8b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "deepseek/deepseek-r1-distill-llama-70b": { + "id": "deepseek/deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "deepseek/deepseek-v3-0324": { + "id": "deepseek/deepseek-v3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek/deepseek-ocr": { + "id": "deepseek/deepseek-ocr", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "baidu/ernie-4.5-vl-28b-a3b-thinking": { + "id": "baidu/ernie-4.5-vl-28b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "baidu/ernie-4.5-vl-424b-a47b": { + "id": "baidu/ernie-4.5-vl-424b-a47b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 16000 + }, + "family": "ernie" + }, + "baidu/ernie-4.5-vl-28b-a3b": { + "id": "baidu/ernie-4.5-vl-28b-a3b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384, + "input": 32768 + }, + "family": "ernie" + }, + "baidu/ernie-4.5-300b-a47b-paddle": { + "id": "baidu/ernie-4.5-300b-a47b-paddle", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 12000 + }, + "family": "ernie" + }, + "baidu/ernie-4.5-21b-a3b": { + "id": "baidu/ernie-4.5-21b-a3b", + "family": "ernie", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 120000, + "output": 8000 + } + }, + "baidu/ernie-4.5-21b-a3b-thinking": { + "id": "baidu/ernie-4.5-21b-a3b-thinking", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "qwen/qwen3-4b-fp8": { + "id": "qwen/qwen3-4b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "qwen/qwen3-32b-fp8": { + "id": "qwen/qwen3-32b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + }, + "family": "qwen" + }, + "qwen/qwen3-30b-a3b-fp8": { + "id": "qwen/qwen3-30b-a3b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + }, + "family": "qwen" + }, + "qwen/qwen3-coder-next": { + "id": "Qwen/Qwen3-Coder-Next", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-vl-235b-a22b-instruct": { + "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "qwen" + }, + "qwen/qwen-mt-plus": { + "id": "qwen/qwen-mt-plus", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, + "qwen/qwen3-omni-30b-a3b-instruct": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "qwen/qwen-2.5-72b-instruct": { + "id": "qwen/qwen-2.5-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "qwen/qwen3-vl-30b-a3b-thinking": { + "id": "qwen/qwen3-vl-30b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen3-vl-235b-a22b-thinking": { + "id": "qwen/qwen3-vl-235b-a22b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen2.5-7b-instruct": { + "id": "Qwen/Qwen2.5-7B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + }, + "family": "qwen" + }, + "qwen/qwen3-235b-a22b-fp8": { + "id": "qwen/qwen3-235b-a22b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + }, + "family": "qwen" + }, + "qwen/qwen3-vl-8b-instruct": { + "id": "qwen/qwen3-vl-8b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "qwen/qwen3-8b-fp8": { + "id": "qwen/qwen3-8b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "qwen/qwen3-omni-30b-a3b-thinking": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + }, + "family": "qwen" + }, + "meta-llama/llama-3-70b-instruct": { + "id": "meta-llama/llama-3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8000 + } + }, + "meta-llama/llama-3-8b-instruct": { + "id": "meta-llama/llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 16384 + } + }, + "mistralai/mistral-nemo": { + "id": "mistralai/mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "sao10k/l3-70b-euryale-v2.1": { + "id": "sao10k/l3-70b-euryale-v2.1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l31-70b-euryale-v2.2": { + "id": "sao10k/l31-70b-euryale-v2.2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3-8b-lunaris": { + "id": "sao10k/l3-8b-lunaris", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3-8b-stheno-v3.2": { + "id": "Sao10K/L3-8B-Stheno-v3.2", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192, + "input": 16384 + }, + "family": "llama" + }, + "xiaomimimo/mimo-v2-flash": { + "id": "XiaomiMiMo/MiMo-V2-Flash", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32000 + } + }, + "nousresearch/hermes-2-pro-llama-3-8b": { + "id": "nousresearch/hermes-2-pro-llama-3-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "gpt-5.3-codex": { + "id": "gpt-5.3-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5-codex": { + "id": "gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gemini-3.1-pro": { + "id": "gemini-3.1-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "trinity-large-preview-free": { + "id": "trinity-large-preview-free", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "gpt-5.1-codex-max": { + "id": "gpt-5.1-codex-max", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "kimi-k2.5-free": { + "id": "kimi-k2.5-free", + "family": "kimi-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "claude-opus-4-1": { + "id": "claude-opus-4-1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "grok-code": { + "id": "grok-code", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "nemotron-3-super-free": { + "id": "nemotron-3-super-free", + "family": "nemotron-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "claude-3-5-haiku": { + "id": "claude-3-5-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "gpt-5.2-codex": { + "id": "gpt-5.2-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "claude-opus-4-6": { + "id": "claude-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "mimo-v2-flash-free": { + "id": "mimo-v2-flash-free", + "family": "mimo-flash-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "gemini-3-flash": { + "id": "gemini-3-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "claude-sonnet-4-6": { + "id": "claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "gpt-5.1": { + "id": "gpt-5.1", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 272000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.3-codex-spark": { + "id": "gpt-5.3-codex-spark", + "family": "gpt-codex-spark", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 100000, + "output": 32000 + } + }, + "qwen3-coder": { + "id": "qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "gpt-5.1-codex-mini": { + "id": "gpt-5.1-codex-mini", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.2": { + "id": "gpt-5.2", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "mimo-v2-omni-free": { + "id": "mimo-v2-omni-free", + "family": "mimo-omni-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 64000 + } + }, + "minimax-m2.1-free": { + "id": "minimax-m2.1-free", + "family": "minimax-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "mimo-v2-pro-free": { + "id": "mimo-v2-pro-free", + "family": "mimo-pro-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 64000 + } + }, + "gpt-5": { + "id": "gpt-5", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 272000, + "input": 272000, + "output": 128000 + } + }, + "glm-5-free": { + "id": "glm-5-free", + "family": "glm-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "gpt-5.4": { + "id": "gpt-5.4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.4-pro": { + "id": "gpt-5.4-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "claude-haiku-4-5": { + "id": "claude-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "gpt-5.1-codex": { + "id": "gpt-5.1-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "big-pickle": { + "id": "big-pickle", + "family": "big-pickle", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "minimax-m2.5-free": { + "id": "minimax-m2.5-free", + "family": "minimax-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "claude-opus-4-5": { + "id": "claude-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-sonnet-4": { + "id": "claude-sonnet-4", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 128000 + } + }, + "glm-4.7-free": { + "id": "glm-4.7-free", + "family": "glm-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "gemini-3-pro": { + "id": "gemini-3-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "claude-sonnet-4-5": { + "id": "claude-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "gpt-5.4-nano": { + "id": "gpt-5.4-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5-nano": { + "id": "gpt-5-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 272000, + "input": 272000, + "output": 128000 + } + }, + "gpt-5.4-mini": { + "id": "gpt-5.4-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "stabilityai/stablediffusionxl": { + "id": "stabilityai/stablediffusionxl", + "family": "stable-diffusion", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 200, + "output": 0 + } + }, + "ideogramai/ideogram-v2": { + "id": "ideogramai/ideogram-v2", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram": { + "id": "ideogramai/ideogram", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram-v2a-turbo": { + "id": "ideogramai/ideogram-v2a-turbo", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "ideogramai/ideogram-v2a": { + "id": "ideogramai/ideogram-v2a", + "family": "ideogram", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 150, + "output": 0 + } + }, + "novita/glm-4.7-flash": { + "id": "novita/glm-4.7-flash", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 65500 + } + }, + "novita/glm-4.7-n": { + "id": "novita/glm-4.7-n", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/glm-4.6": { + "id": "novita/glm-4.6", + "family": "glm", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "novita/minimax-m2.1": { + "id": "novita/minimax-m2.1", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/kimi-k2.5": { + "id": "novita/kimi-k2.5", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 262144 + } + }, + "novita/glm-4.7": { + "id": "novita/glm-4.7", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "novita/kimi-k2-thinking": { + "id": "novita/kimi-k2-thinking", + "family": "kimi", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 0 + } + }, + "novita/glm-4.6v": { + "id": "novita/glm-4.6v", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32768 + } + }, + "google/gemini-3.1-pro": { + "id": "google/gemini-3.1-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/lyria": { + "id": "google/lyria", + "family": "lyria", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "google/gemini-3-flash": { + "id": "google/gemini-3-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + }, + "family": "gemini-flash" + }, + "google/imagen-3": { + "id": "google/imagen-3", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/veo-3.1": { + "id": "google/veo-3.1", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/imagen-3-fast": { + "id": "google/imagen-3-fast", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/nano-banana-pro": { + "id": "google/nano-banana-pro", + "family": "nano-banana", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 65536, + "output": 0 + } + }, + "google/veo-2": { + "id": "google/veo-2", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/imagen-4-ultra": { + "id": "google/imagen-4-ultra", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/nano-banana": { + "id": "google/nano-banana", + "family": "nano-banana", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 65536, + "output": 0 + } + }, + "google/veo-3.1-fast": { + "id": "google/veo-3.1-fast", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-deep-research": { + "id": "google/gemini-deep-research", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 0 + } + }, + "google/veo-3": { + "id": "google/veo-3", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/imagen-4": { + "id": "google/imagen-4", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-2.0-flash-lite": { + "id": "google/gemini-2.0-flash-lite", + "family": "gemini-flash-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemini-3.1-flash-lite": { + "id": "google/gemini-3.1-flash-lite", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3-pro": { + "id": "google/gemini-3-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.0-flash": { + "id": "google/gemini-2.0-flash", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/veo-3-fast": { + "id": "google/veo-3-fast", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/imagen-4-fast": { + "id": "google/imagen-4-fast", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "lumalabs/ray2": { + "id": "lumalabs/ray2", + "family": "ray", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 5000, + "output": 0 + } + }, + "poetools/claude-code": { + "id": "poetools/claude-code", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-5-pro": { + "id": "openai/gpt-5-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + } + }, + "openai/gpt-5.1-codex-max": { + "id": "openai/gpt-5.1-codex-max", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 400000 + }, + "family": "gpt-codex" + }, + "openai/o3-deep-research": { + "id": "openai/o3-deep-research", + "family": "o", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/o4-mini-deep-research": { + "id": "openai/o4-mini-deep-research", + "family": "o-mini", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/gpt-5-chat": { + "id": "openai/gpt-5-chat", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + } + }, + "openai/gpt-4-classic": { + "id": "openai/gpt-4-classic", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "openai/gpt-5.3-instant": { + "id": "openai/gpt-5.3-instant", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + } + }, + "openai/gpt-image-1.5": { + "id": "openai/gpt-image-1.5", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "openai/gpt-4.1-nano": { + "id": "openai/gpt-4.1-nano", + "family": "gpt-nano", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768, + "input": 1047576 + } + }, + "openai/gpt-image-1-mini": { + "id": "openai/gpt-image-1-mini", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/sora-2-pro": { + "id": "openai/sora-2-pro", + "family": "sora", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-4o-aug": { + "id": "openai/gpt-4o-aug", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-image-1": { + "id": "openai/gpt-image-1", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "openai/sora-2": { + "id": "openai/sora-2", + "family": "sora", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "openai/gpt-3.5-turbo-raw": { + "id": "openai/gpt-3.5-turbo-raw", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4524, + "output": 2048 + } + }, + "openai/gpt-4o-mini-search": { + "id": "openai/gpt-4o-mini-search", + "family": "gpt-mini", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-4.1-mini": { + "id": "openai/gpt-4.1-mini", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768, + "input": 1047576 + } + }, + "openai/o1-pro": { + "id": "openai/o1-pro", + "family": "o-pro", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/chatgpt-4o-latest": { + "id": "openai/chatgpt-4o-latest", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "openai/dall-e-3": { + "id": "openai/dall-e-3", + "family": "dall-e", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 800, + "output": 0 + } + }, + "openai/gpt-4o-search": { + "id": "openai/gpt-4o-search", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-4-classic-0314": { + "id": "openai/gpt-4-classic-0314", + "family": "gpt", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "openai/gpt-3.5-turbo-instruct": { + "id": "openai/gpt-3.5-turbo-instruct", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4095, + "output": 4096, + "input": 4096 + } + }, + "openai/gpt-5.2-instant": { + "id": "openai/gpt-5.2-instant", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/o3-mini-high": { + "id": "openai/o3-mini-high", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + } + }, + "openai/gpt-5.1-instant": { + "id": "openai/gpt-5.1-instant", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + } + }, + "topazlabs-co/topazlabs": { + "id": "topazlabs-co/topazlabs", + "family": "topazlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 204, + "output": 0 + } + }, + "runwayml/runway": { + "id": "runwayml/runway", + "family": "runway", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 256, + "output": 0 + } + }, + "runwayml/runway-gen-4-turbo": { + "id": "runwayml/runway-gen-4-turbo", + "family": "runway", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "video" + ] + }, + "limit": { + "context": 256, + "output": 0 + } + }, + "anthropic/claude-sonnet-3.5-june": { + "id": "anthropic/claude-sonnet-3.5-june", + "family": "claude-sonnet", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-sonnet-3.5": { + "id": "anthropic/claude-sonnet-3.5", + "family": "claude-sonnet", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-haiku-3": { + "id": "anthropic/claude-haiku-3", + "family": "claude-haiku", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-haiku-3.5": { + "id": "anthropic/claude-haiku-3.5", + "family": "claude-haiku", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 189096, + "output": 8192 + } + }, + "anthropic/claude-sonnet-3.7": { + "id": "anthropic/claude-sonnet-3.7", + "family": "claude-sonnet", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 128000 + } + }, + "trytako/tako": { + "id": "trytako/tako", + "family": "tako", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2048, + "output": 0 + } + }, + "elevenlabs/elevenlabs-music": { + "id": "elevenlabs/elevenlabs-music", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 2000, + "output": 0 + } + }, + "elevenlabs/elevenlabs-v3": { + "id": "elevenlabs/elevenlabs-v3", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "elevenlabs/elevenlabs-v2.5-turbo": { + "id": "elevenlabs/elevenlabs-v2.5-turbo", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "cerebras/llama-3.1-8b-cs": { + "id": "cerebras/llama-3.1-8b-cs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/gpt-oss-120b-cs": { + "id": "cerebras/gpt-oss-120b-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/qwen3-235b-2507-cs": { + "id": "cerebras/qwen3-235b-2507-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/llama-3.3-70b-cs": { + "id": "cerebras/llama-3.3-70b-cs", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "cerebras/qwen3-32b-cs": { + "id": "cerebras/qwen3-32b-cs", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "xai/grok-4-fast-reasoning": { + "id": "xai/grok-4-fast-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 256000 + } + }, + "xai/grok-3": { + "id": "xai/grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "xai/grok-code-fast-1": { + "id": "xai/grok-code-fast-1", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000 + } + }, + "xai/grok-4.1-fast-reasoning": { + "id": "xai/grok-4.1-fast-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "xai/grok-4": { + "id": "xai/grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "xai/grok-4.1-fast-non-reasoning": { + "id": "xai/grok-4.1-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "xai/grok-3-mini": { + "id": "xai/grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "xai/grok-4-fast-non-reasoning": { + "id": "xai/grok-4-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "deepseek.r1-v1:0": { + "id": "deepseek.r1-v1:0", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta.llama3-1-70b-instruct-v1:0": { + "id": "meta.llama3-1-70b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen.qwen3-coder-480b-a35b-v1:0": { + "id": "qwen.qwen3-coder-480b-a35b-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "eu.anthropic.claude-sonnet-4-6": { + "id": "eu.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "eu.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "eu.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.mistral-large-3-675b-instruct": { + "id": "mistral.mistral-large-3-675b-instruct", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "openai.gpt-oss-120b-1:0": { + "id": "openai.gpt-oss-120b-1:0", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "us.anthropic.claude-opus-4-20250514-v1:0": { + "id": "us.anthropic.claude-opus-4-20250514-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "nvidia.nemotron-nano-12b-v2": { + "id": "nvidia.nemotron-nano-12b-v2", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-3-7-sonnet-20250219-v1:0": { + "id": "anthropic.claude-3-7-sonnet-20250219-v1:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic.claude-sonnet-4-6": { + "id": "anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "minimax.minimax-m2.1": { + "id": "minimax.minimax-m2.1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "global.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "global.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.ministral-3-8b-instruct": { + "id": "mistral.ministral-3-8b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai.gpt-oss-safeguard-20b": { + "id": "openai.gpt-oss-safeguard-20b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "amazon.nova-lite-v1:0": { + "id": "amazon.nova-lite-v1:0", + "family": "nova-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "mistral.pixtral-large-2502-v1:0": { + "id": "mistral.pixtral-large-2502-v1:0", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "google.gemma-3-12b-it": { + "id": "google.gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "meta.llama3-1-8b-instruct-v1:0": { + "id": "meta.llama3-1-8b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral.devstral-2-123b": { + "id": "mistral.devstral-2-123b", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "meta.llama4-maverick-17b-instruct-v1:0": { + "id": "meta.llama4-maverick-17b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "mistral.ministral-3-14b-instruct": { + "id": "mistral.ministral-3-14b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "minimax.minimax-m2": { + "id": "minimax.minimax-m2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204608, + "output": 128000 + } + }, + "amazon.nova-micro-v1:0": { + "id": "amazon.nova-micro-v1:0", + "family": "nova-micro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "anthropic.claude-3-5-sonnet-20241022-v2:0": { + "id": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "nvidia.nemotron-nano-3-30b": { + "id": "nvidia.nemotron-nano-3-30b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen.qwen3-vl-235b-a22b": { + "id": "qwen.qwen3-vl-235b-a22b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "global.anthropic.claude-opus-4-6-v1": { + "id": "global.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "writer.palmyra-x4-v1:0": { + "id": "writer.palmyra-x4-v1:0", + "family": "palmyra", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 122880, + "output": 8192 + } + }, + "minimax.minimax-m2.5": { + "id": "minimax.minimax-m2.5", + "family": "minimax-m2.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 131072 + } + }, + "amazon.nova-pro-v1:0": { + "id": "amazon.nova-pro-v1:0", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "us.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "us.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "meta.llama3-2-90b-instruct-v1:0": { + "id": "meta.llama3-2-90b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "us.anthropic.claude-opus-4-6-v1": { + "id": "us.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "google.gemma-3-4b-it": { + "id": "google.gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-opus-4-6-v1": { + "id": "anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "zai.glm-4.7-flash": { + "id": "zai.glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "anthropic.claude-opus-4-20250514-v1:0": { + "id": "anthropic.claude-opus-4-20250514-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "global.anthropic.claude-sonnet-4-6": { + "id": "global.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "meta.llama3-2-1b-instruct-v1:0": { + "id": "meta.llama3-2-1b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4096 + } + }, + "anthropic.claude-opus-4-1-20250805-v1:0": { + "id": "anthropic.claude-opus-4-1-20250805-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "meta.llama4-scout-17b-instruct-v1:0": { + "id": "meta.llama4-scout-17b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 3500000, + "output": 16384 + } + }, + "deepseek.v3.2": { + "id": "deepseek.v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 81920 + } + }, + "deepseek.v3-v1:0": { + "id": "deepseek.v3-v1:0", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 81920 + } + }, + "mistral.ministral-3-3b-instruct": { + "id": "mistral.ministral-3-3b-instruct", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "global.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "global.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "nvidia.nemotron-nano-9b-v2": { + "id": "nvidia.nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "writer.palmyra-x5-v1:0": { + "id": "writer.palmyra-x5-v1:0", + "family": "palmyra", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1040000, + "output": 8192 + } + }, + "meta.llama3-3-70b-instruct-v1:0": { + "id": "meta.llama3-3-70b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "zai.glm-4.7": { + "id": "zai.glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "moonshot.kimi-k2-thinking": { + "id": "moonshot.kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "anthropic.claude-3-haiku-20240307-v1:0": { + "id": "anthropic.claude-3-haiku-20240307-v1:0", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "us.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "openai.gpt-oss-20b-1:0": { + "id": "openai.gpt-oss-20b-1:0", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "us.anthropic.claude-sonnet-4-6": { + "id": "us.anthropic.claude-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "meta.llama3-2-11b-instruct-v1:0": { + "id": "meta.llama3-2-11b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "eu.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "eu.anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "meta.llama3-1-405b-instruct-v1:0": { + "id": "meta.llama3-1-405b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen.qwen3-next-80b-a3b": { + "id": "qwen.qwen3-next-80b-a3b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "us.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "us.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen.qwen3-coder-30b-a3b-v1:0": { + "id": "qwen.qwen3-coder-30b-a3b-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "us.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "us.anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "qwen.qwen3-235b-a22b-2507-v1:0": { + "id": "qwen.qwen3-235b-a22b-2507-v1:0", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "openai.gpt-oss-safeguard-120b": { + "id": "openai.gpt-oss-safeguard-120b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "anthropic.claude-3-5-sonnet-20240620-v1:0": { + "id": "anthropic.claude-3-5-sonnet-20240620-v1:0", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "mistral.voxtral-small-24b-2507": { + "id": "mistral.voxtral-small-24b-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "anthropic.claude-haiku-4-5-20251001-v1:0", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "meta.llama3-2-3b-instruct-v1:0": { + "id": "meta.llama3-2-3b-instruct-v1:0", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4096 + } + }, + "google.gemma-3-27b-it": { + "id": "google.gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 8192 + } + }, + "us.anthropic.claude-opus-4-1-20250805-v1:0": { + "id": "us.anthropic.claude-opus-4-1-20250805-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "global.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "global.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-3-5-haiku-20241022-v1:0": { + "id": "anthropic.claude-3-5-haiku-20241022-v1:0", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "zai.glm-5": { + "id": "zai.glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "eu.anthropic.claude-sonnet-4-20250514-v1:0": { + "id": "eu.anthropic.claude-sonnet-4-20250514-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "anthropic.claude-opus-4-5-20251101-v1:0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "eu.anthropic.claude-opus-4-6-v1": { + "id": "eu.anthropic.claude-opus-4-6-v1", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "amazon.nova-premier-v1:0": { + "id": "amazon.nova-premier-v1:0", + "family": "nova", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "amazon.nova-2-lite-v1:0": { + "id": "amazon.nova-2-lite-v1:0", + "family": "nova", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen.qwen3-32b-v1:0": { + "id": "qwen.qwen3-32b-v1:0", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "mistral.magistral-small-2509": { + "id": "mistral.magistral-small-2509", + "family": "magistral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 40000 + } + }, + "moonshotai.kimi-k2.5": { + "id": "moonshotai.kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral.voxtral-mini-3b-2507": { + "id": "mistral.voxtral-mini-3b-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "global.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "global.anthropic.claude-sonnet-4-5-20250929-v1:0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "ring-1t": { + "id": "Ring-1T", + "family": "ring", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "ling-1t": { + "id": "Ling-1T", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "phi-3-small-8k-instruct": { + "id": "phi-3-small-8k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "gpt-4o": { + "id": "gpt-4o", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 64000 + } + }, + "codestral-2501": { + "id": "codestral-2501", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral-small-2503": { + "id": "mistral-small-2503", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "o1-mini": { + "id": "o1-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536 + } + }, + "gpt-3.5-turbo-instruct": { + "id": "gpt-3.5-turbo-instruct", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "gpt-4": { + "id": "gpt-4", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "gpt-3.5-turbo-1106": { + "id": "gpt-3.5-turbo-1106", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "phi-4-reasoning": { + "id": "phi-4-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "phi-3-mini-128k-instruct": { + "id": "phi-3-mini-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-5-mini": { + "id": "gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 272000, + "output": 128000, + "input": 272000 + } + }, + "grok-4-fast-non-reasoning": { + "id": "grok-4-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "o3-mini": { + "id": "o3-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "cohere-embed-v3-english": { + "id": "cohere-embed-v3-english", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "phi-3-medium-4k-instruct": { + "id": "phi-3-medium-4k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "cohere-embed-v3-multilingual": { + "id": "cohere-embed-v3-multilingual", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "gpt-3.5-turbo-0125": { + "id": "gpt-3.5-turbo-0125", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "phi-4-mini-reasoning": { + "id": "phi-4-mini-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mistral-large-2411": { + "id": "mistral-large-2411", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta-llama-3.1-8b-instruct": { + "id": "meta-llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "o1-preview": { + "id": "o1-preview", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta-llama-3.1-70b-instruct": { + "id": "meta-llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "phi-3-mini-4k-instruct": { + "id": "phi-3-mini-4k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "codex-mini": { + "id": "codex-mini", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "phi-4-reasoning-plus": { + "id": "phi-4-reasoning-plus", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "gpt-4.1-mini": { + "id": "gpt-4.1-mini", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768 + } + }, + "phi-4": { + "id": "phi-4", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "o4-mini": { + "id": "o4-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-4-32k": { + "id": "gpt-4-32k", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "grok-3-mini": { + "id": "grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "cohere-embed-v-4-0": { + "id": "cohere-embed-v-4-0", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 1536 + } + }, + "mistral-nemo": { + "id": "mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "gpt-4-turbo": { + "id": "gpt-4-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-4.1": { + "id": "gpt-4.1", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768, + "input": 64000 + } + }, + "model-router": { + "id": "model-router", + "family": "model-router", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "text-embedding-3-large": { + "id": "text-embedding-3-large", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 3072 + }, + "temperature": false + }, + "gpt-3.5-turbo-0613": { + "id": "gpt-3.5-turbo-0613", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "cohere-command-r-08-2024": { + "id": "cohere-command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "gpt-4.1-nano": { + "id": "gpt-4.1-nano", + "family": "gpt-nano", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768 + } + }, + "deepseek-v3.2-speciale": { + "id": "deepseek-v3.2-speciale", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "phi-4-mini": { + "id": "phi-4-mini", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "text-embedding-3-small": { + "id": "text-embedding-3-small", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 1536 + }, + "temperature": false + }, + "gpt-3.5-turbo-0301": { + "id": "gpt-3.5-turbo-0301", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "meta-llama-3-70b-instruct": { + "id": "meta-llama-3-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "llama-3.2-11b-vision-instruct": { + "id": "llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "o3": { + "id": "o3", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "meta-llama-3-8b-instruct": { + "id": "meta-llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "gpt-5.1-chat": { + "id": "gpt-5.1-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-4": { + "id": "grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "gpt-5-chat": { + "id": "gpt-5-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "gpt-5.2-chat": { + "id": "gpt-5.2-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "cohere-command-r-plus-08-2024": { + "id": "cohere-command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "meta-llama-3.1-405b-instruct": { + "id": "meta-llama-3.1-405b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "llama-4-scout-17b-16e-instruct": { + "id": "llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "o1": { + "id": "o1", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "mistral-medium-2505": { + "id": "mistral-medium-2505", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "cohere-command-a": { + "id": "cohere-command-a", + "family": "command-a", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + } + }, + "phi-3.5-mini-instruct": { + "id": "phi-3.5-mini-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "grok-code-fast-1": { + "id": "grok-code-fast-1", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000, + "input": 128000 + } + }, + "llama-3.2-90b-vision-instruct": { + "id": "llama-3.2-90b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "grok-3": { + "id": "grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "ministral-3b": { + "id": "ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "gpt-4-turbo-vision": { + "id": "gpt-4-turbo-vision", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "phi-3.5-moe-instruct": { + "id": "phi-3.5-moe-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "mai-ds-r1": { + "id": "mai-ds-r1", + "family": "mai", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "phi-4-multimodal": { + "id": "phi-4-multimodal", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "phi-3-medium-128k-instruct": { + "id": "phi-3-medium-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "grok-4-fast-reasoning": { + "id": "grok-4-fast-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "text-embedding-ada-002": { + "id": "text-embedding-ada-002", + "family": "text-embedding", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + }, + "temperature": false + }, + "gpt-4o-mini": { + "id": "gpt-4o-mini", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "phi-3-small-128k-instruct": { + "id": "phi-3-small-128k-instruct", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "gpt-5-pro": { + "id": "gpt-5-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 272000, + "input": 272000 + } + }, + "qwen-vl-plus": { + "id": "qwen-vl-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-vl-max": { + "id": "qwen-vl-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-14b": { + "id": "qwen3-14b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-coder-flash": { + "id": "qwen3-coder-flash", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen3-vl-30b-a3b": { + "id": "qwen3-vl-30b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen3-asr-flash": { + "id": "qwen3-asr-flash", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 53248, + "output": 4096 + } + }, + "qwen-max": { + "id": "qwen-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192, + "input": 32000 + } + }, + "qwen2-5-7b-instruct": { + "id": "qwen2-5-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen2-5-vl-72b-instruct": { + "id": "qwen2-5-vl-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen2-5-14b-instruct": { + "id": "qwen2-5-14b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-8b": { + "id": "qwen3-8b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qvq-max": { + "id": "qvq-max", + "family": "qvq", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192, + "input": 128000 + } + }, + "qwen2-5-omni-7b": { + "id": "qwen2-5-omni-7b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "qwen2-5-vl-7b-instruct": { + "id": "qwen2-5-vl-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-omni-turbo-realtime": { + "id": "qwen-omni-turbo-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "qwen-omni-turbo": { + "id": "qwen-omni-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 32768, + "output": 2048 + } + }, + "qwen-mt-plus": { + "id": "qwen-mt-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, + "qwen3-livetranslate-flash-realtime": { + "id": "qwen3-livetranslate-flash-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 53248, + "output": 4096 + } + }, + "qwen-plus": { + "id": "qwen-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768, + "input": 995904 + } + }, + "qwen2-5-32b-instruct": { + "id": "qwen2-5-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-omni-flash": { + "id": "qwen3-omni-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 65536, + "output": 16384 + } + }, + "qwen-flash": { + "id": "qwen-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen2-5-72b-instruct": { + "id": "qwen2-5-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-omni-flash-realtime": { + "id": "qwen3-omni-flash-realtime", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 65536, + "output": 16384 + } + }, + "qwen-vl-ocr": { + "id": "qwen-vl-ocr", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 34096, + "output": 4096 + } + }, + "qwq-plus": { + "id": "qwq-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-vl-235b-a22b": { + "id": "qwen3-vl-235b-a22b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen-plus-character-ja": { + "id": "qwen-plus-character-ja", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 512 + } + }, + "qwen-mt-turbo": { + "id": "qwen-mt-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192 + } + }, + "@cf/zai-org/glm-4.7-flash": { + "id": "@cf/zai-org/glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "@cf/nvidia/nemotron-3-120b-a12b": { + "id": "@cf/nvidia/nemotron-3-120b-a12b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "@cf/ibm-granite/granite-4.0-h-micro": { + "id": "@cf/ibm-granite/granite-4.0-h-micro", + "family": "granite", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/baai/bge-small-en-v1.5": { + "id": "@cf/baai/bge-small-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/baai/bge-large-en-v1.5": { + "id": "@cf/baai/bge-large-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/baai/bge-reranker-base": { + "id": "@cf/baai/bge-reranker-base", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/baai/bge-m3": { + "id": "@cf/baai/bge-m3", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/baai/bge-base-en-v1.5": { + "id": "@cf/baai/bge-base-en-v1.5", + "family": "bge", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/pfnet/plamo-embedding-1b": { + "id": "@cf/pfnet/plamo-embedding-1b", + "family": "plamo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b": { + "id": "@cf/deepseek-ai/deepseek-r1-distill-qwen-32b", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/facebook/bart-large-cnn": { + "id": "@cf/facebook/bart-large-cnn", + "family": "bart", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/mistral/mistral-7b-instruct-v0.1": { + "id": "@cf/mistral/mistral-7b-instruct-v0.1", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/myshell-ai/melotts": { + "id": "@cf/myshell-ai/melotts", + "family": "melotts", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/pipecat-ai/smart-turn-v2": { + "id": "@cf/pipecat-ai/smart-turn-v2", + "family": "smart-turn", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/moonshotai/kimi-k2.5": { + "id": "@cf/moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "@cf/google/gemma-3-12b-it": { + "id": "@cf/google/gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/qwen/qwq-32b": { + "id": "@cf/qwen/qwq-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/qwen/qwen3-30b-a3b-fp8": { + "id": "@cf/qwen/qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/qwen/qwen2.5-coder-32b-instruct": { + "id": "@cf/qwen/qwen2.5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/qwen/qwen3-embedding-0.6b": { + "id": "@cf/qwen/qwen3-embedding-0.6b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.1-8b-instruct-fp8": { + "id": "@cf/meta/llama-3.1-8b-instruct-fp8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3-8b-instruct-awq": { + "id": "@cf/meta/llama-3-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.1-8b-instruct-awq": { + "id": "@cf/meta/llama-3.1-8b-instruct-awq", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-4-scout-17b-16e-instruct": { + "id": "@cf/meta/llama-4-scout-17b-16e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.2-11b-vision-instruct": { + "id": "@cf/meta/llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.2-3b-instruct": { + "id": "@cf/meta/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-guard-3-8b": { + "id": "@cf/meta/llama-guard-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.2-1b-instruct": { + "id": "@cf/meta/llama-3.2-1b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.3-70b-instruct-fp8-fast": { + "id": "@cf/meta/llama-3.3-70b-instruct-fp8-fast", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3.1-8b-instruct": { + "id": "@cf/meta/llama-3.1-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/m2m100-1.2b": { + "id": "@cf/meta/m2m100-1.2b", + "family": "m2m", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-2-7b-chat-fp16": { + "id": "@cf/meta/llama-2-7b-chat-fp16", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/meta/llama-3-8b-instruct": { + "id": "@cf/meta/llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/mistralai/mistral-small-3.1-24b-instruct": { + "id": "@cf/mistralai/mistral-small-3.1-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/deepgram/aura-2-es": { + "id": "@cf/deepgram/aura-2-es", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/deepgram/nova-3": { + "id": "@cf/deepgram/nova-3", + "family": "nova", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/deepgram/aura-2-en": { + "id": "@cf/deepgram/aura-2-en", + "family": "aura", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/openai/gpt-oss-120b": { + "id": "@cf/openai/gpt-oss-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/openai/gpt-oss-20b": { + "id": "@cf/openai/gpt-oss-20b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/ai4bharat/indictrans2-en-indic-1b": { + "id": "@cf/ai4bharat/indictrans2-en-indic-1B", + "family": "indictrans", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/huggingface/distilbert-sst-2-int8": { + "id": "@cf/huggingface/distilbert-sst-2-int8", + "family": "distilbert", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/aisingapore/gemma-sea-lion-v4-27b-it": { + "id": "@cf/aisingapore/gemma-sea-lion-v4-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "llama3-70b-8192": { + "id": "llama3-70b-8192", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "qwen-qwq-32b": { + "id": "qwen-qwq-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "llama-3.1-8b-instant": { + "id": "llama-3.1-8b-instant", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32678 + } + }, + "llama-guard-3-8b": { + "id": "llama-guard-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "llama3-8b-8192": { + "id": "llama3-8b-8192", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "mistral-saba-24b": { + "id": "mistral-saba-24b", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "llama-3.3-70b-versatile": { + "id": "llama-3.3-70b-versatile", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32678 + } + }, + "gemma2-9b-it": { + "id": "gemma2-9b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "meta-llama/llama-guard-4-12b": { + "id": "meta-llama/llama-guard-4-12b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + } + }, + "meta-llama/llama-4-maverick-17b-128e-instruct": { + "id": "meta-llama/llama-4-maverick-17b-128e-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "zai-org/glm-5-fp8": { + "id": "zai-org/GLM-5-FP8", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "nvidia/nvidia-nemotron-3-super-120b-a12b-fp8": { + "id": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "openpipe/qwen3-14b-instruct": { + "id": "OpenPipe/Qwen3-14B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "coding-glm-4.7-free": { + "id": "coding-glm-4.7-free", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "coding-minimax-m2.1-free": { + "id": "coding-minimax-m2.1-free", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "claude-opus-4-6-think": { + "id": "claude-opus-4-6-think", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "gemini-3-pro-preview-search": { + "id": "gemini-3-pro-preview-search", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65000 + } + }, + "deepseek-v3.2-think": { + "id": "deepseek-v3.2-think", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 64000 + } + }, + "gemini-3-pro-preview": { + "id": "gemini-3-pro-preview", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "deepseek-v3.2-fast": { + "id": "deepseek-v3.2-fast", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "coding-glm-4.7": { + "id": "coding-glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "coding-glm-5-free": { + "id": "coding-glm-5-free", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "claude-sonnet-4-6-think": { + "id": "claude-sonnet-4-6-think", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "k2p5": { + "id": "k2p5", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "devstral-medium-2507": { + "id": "devstral-medium-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "labs-devstral-small-2512": { + "id": "labs-devstral-small-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "devstral-medium-latest": { + "id": "devstral-medium-latest", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "open-mistral-7b": { + "id": "open-mistral-7b", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 8000 + } + }, + "mistral-small-2506": { + "id": "mistral-small-2506", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "codestral-latest": { + "id": "codestral-latest", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "ministral-8b-latest": { + "id": "ministral-8b-latest", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "magistral-small": { + "id": "magistral-small", + "family": "magistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral-large-2512": { + "id": "mistral-large-2512", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 262144 + } + }, + "ministral-3b-latest": { + "id": "ministral-3b-latest", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral-embed": { + "id": "mistral-embed", + "family": "mistral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 3072 + } + }, + "devstral-small-2505": { + "id": "devstral-small-2505", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "pixtral-12b": { + "id": "pixtral-12b", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "open-mixtral-8x7b": { + "id": "open-mixtral-8x7b", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "pixtral-large-latest": { + "id": "pixtral-large-latest", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "devstral-2512": { + "id": "devstral-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "mistral-large-latest": { + "id": "mistral-large-latest", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mistral-medium-2508": { + "id": "mistral-medium-2508", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mistral-small-latest": { + "id": "mistral-small-latest", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "open-mixtral-8x22b": { + "id": "open-mixtral-8x22b", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "mistral-medium-latest": { + "id": "mistral-medium-latest", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "devstral-small-2507": { + "id": "devstral-small-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "magistral-medium-latest": { + "id": "magistral-medium-latest", + "family": "magistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "gpt-4o-2024-11-20": { + "id": "gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-opus-4-5-20251101": { + "id": "claude-opus-4-5-20251101", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000, + "input": 200000 + } + }, + "gpt-5.2-chat-latest": { + "id": "gpt-5.2-chat-latest", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-4-0709": { + "id": "grok-4-0709", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "gpt-5.3-codex-xhigh": { + "id": "gpt-5.3-codex-xhigh", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "grok-4-1-fast-non-reasoning": { + "id": "grok-4-1-fast-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000, + "input": 128000 + } + }, + "gemini-3.1-flash-lite-preview": { + "id": "gemini-3.1-flash-lite-preview", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "claude-opus-4-20250514": { + "id": "claude-opus-4-20250514", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000, + "input": 200000 + } + }, + "claude-sonnet-4-5-20250929": { + "id": "claude-sonnet-4-5-20250929", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000, + "input": 1000000 + } + }, + "o3-pro": { + "id": "o3-pro", + "family": "o-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gemini-3.1-pro-preview": { + "id": "gemini-3.1-pro-preview", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + } + }, + "claude-3-7-sonnet-20250219": { + "id": "claude-3-7-sonnet-20250219", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 16000, + "input": 200000 + } + }, + "claude-haiku-4-5-20251001": { + "id": "claude-haiku-4-5-20251001", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 200000 + } + }, + "kimi-k2-turbo-preview": { + "id": "kimi-k2-turbo-preview", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen-2.5-coder-32b": { + "id": "qwen-2.5-coder-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "route-llm": { + "id": "route-llm", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "gpt-5.3-chat-latest": { + "id": "gpt-5.3-chat-latest", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "claude-sonnet-4-20250514": { + "id": "claude-sonnet-4-20250514", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 200000 + } + }, + "gpt-5.1-chat-latest": { + "id": "gpt-5.1-chat-latest", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-opus-4-1-20250805": { + "id": "claude-opus-4-1-20250805", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000, + "input": 200000 + } + }, + "meta-llama/meta-llama-3.1-405b-instruct-turbo": { + "id": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen/qwen2.5-72b-instruct": { + "id": "Qwen/Qwen2.5-72B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "accounts/fireworks/routers/kimi-k2p5-turbo": { + "id": "accounts/fireworks/routers/kimi-k2p5-turbo", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "accounts/fireworks/models/kimi-k2-instruct": { + "id": "accounts/fireworks/models/kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "accounts/fireworks/models/glm-4p7": { + "id": "accounts/fireworks/models/glm-4p7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 198000 + } + }, + "accounts/fireworks/models/glm-5": { + "id": "accounts/fireworks/models/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "accounts/fireworks/models/deepseek-v3p1": { + "id": "accounts/fireworks/models/deepseek-v3p1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "accounts/fireworks/models/minimax-m2p1": { + "id": "accounts/fireworks/models/minimax-m2p1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "accounts/fireworks/models/glm-4p5-air": { + "id": "accounts/fireworks/models/glm-4p5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "accounts/fireworks/models/deepseek-v3p2": { + "id": "accounts/fireworks/models/deepseek-v3p2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 160000 + } + }, + "accounts/fireworks/models/minimax-m2p5": { + "id": "accounts/fireworks/models/minimax-m2p5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + } + }, + "accounts/fireworks/models/gpt-oss-120b": { + "id": "accounts/fireworks/models/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "accounts/fireworks/models/kimi-k2p5": { + "id": "accounts/fireworks/models/kimi-k2p5", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "accounts/fireworks/models/kimi-k2-thinking": { + "id": "accounts/fireworks/models/kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "accounts/fireworks/models/glm-4p5": { + "id": "accounts/fireworks/models/glm-4p5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "accounts/fireworks/models/gpt-oss-20b": { + "id": "accounts/fireworks/models/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "step-3.5-flash": { + "id": "step-3.5-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "step-2-16k": { + "id": "step-2-16k", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "step-1-32k": { + "id": "step-1-32k", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "duo-chat-gpt-5-2-codex": { + "id": "duo-chat-gpt-5-2-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-opus-4-6": { + "id": "duo-chat-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "duo-chat-gpt-5-mini": { + "id": "duo-chat-gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-3-codex": { + "id": "duo-chat-gpt-5-3-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-sonnet-4-5": { + "id": "duo-chat-sonnet-4-5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-haiku-4-5": { + "id": "duo-chat-haiku-4-5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-gpt-5-codex": { + "id": "duo-chat-gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-4-nano": { + "id": "duo-chat-gpt-5-4-nano", + "family": "gpt-nano", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-2": { + "id": "duo-chat-gpt-5-2", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-gpt-5-4-mini": { + "id": "duo-chat-gpt-5-4-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "duo-chat-sonnet-4-6": { + "id": "duo-chat-sonnet-4-6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "duo-chat-gpt-5-4": { + "id": "duo-chat-gpt-5-4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + } + }, + "duo-chat-opus-4-5": { + "id": "duo-chat-opus-4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "duo-chat-gpt-5-1": { + "id": "duo-chat-gpt-5-1", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "nex-agi/deepseek-v3.1-nex-n1": { + "id": "nex-agi/deepseek-v3.1-nex-n1", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + } + }, + "deepseek-ai/deepseek-r1-distill-qwen-32b": { + "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "deepseek-ai/deepseek-r1-distill-qwen-14b": { + "id": "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "deepseek-ai/deepseek-v3.2-exp": { + "id": "deepseek-ai/deepseek-v3.2-exp", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536, + "input": 163840 + } + }, + "deepseek-ai/deepseek-vl2": { + "id": "deepseek-ai/deepseek-vl2", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4000, + "output": 4000 + } + }, + "deepseek-ai/deepseek-v3": { + "id": "deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "bytedance-seed/seed-oss-36b-instruct": { + "id": "ByteDance-Seed/Seed-OSS-36B-Instruct", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "tencent/hunyuan-a13b-instruct": { + "id": "tencent/hunyuan-a13b-instruct", + "family": "hunyuan", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "tencent/hunyuan-mt-7b": { + "id": "tencent/Hunyuan-MT-7B", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192, + "input": 8192 + } + }, + "inclusionai/ling-flash-2.0": { + "id": "inclusionAI/Ling-flash-2.0", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "inclusionai/ring-flash-2.0": { + "id": "inclusionAI/Ring-flash-2.0", + "family": "ring", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "inclusionai/ling-mini-2.0": { + "id": "inclusionAI/Ling-mini-2.0", + "family": "ling", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "baidu/ernie-4.5-300b-a47b": { + "id": "baidu/ernie-4.5-300b-a47b", + "family": "ernie", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384, + "input": 131072 + } + }, + "qwen/qwen3-vl-32b-instruct": { + "id": "qwen/qwen3-vl-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen2.5-vl-7b-instruct": { + "id": "Qwen/Qwen2.5-VL-7B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen2.5-32b-instruct": { + "id": "Qwen/Qwen2.5-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen3-8b": { + "id": "qwen/qwen3-8b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 8192 + } + }, + "qwen/qwen2.5-14b-instruct": { + "id": "Qwen/Qwen2.5-14B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen2.5-72b-instruct-128k": { + "id": "Qwen/Qwen2.5-72B-Instruct-128K", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4000 + } + }, + "qwen/qwen3-omni-30b-a3b-captioner": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Captioner", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "qwen/qwen3-vl-8b-thinking": { + "id": "qwen/qwen3-vl-8b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen3-vl-32b-thinking": { + "id": "Qwen/Qwen3-VL-32B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-14b": { + "id": "Qwen/Qwen3-14B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "thudm/glm-4-32b-0414": { + "id": "THUDM/GLM-4-32B-0414", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536, + "input": 128000 + } + }, + "thudm/glm-4-9b-0414": { + "id": "THUDM/GLM-4-9B-0414", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8000, + "input": 32000 + } + }, + "thudm/glm-z1-32b-0414": { + "id": "THUDM/GLM-Z1-32B-0414", + "family": "glm-z", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536, + "input": 128000 + } + }, + "thudm/glm-z1-9b-0414": { + "id": "THUDM/GLM-Z1-9B-0414", + "family": "glm-z", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8000, + "input": 32000 + } + }, + "essentialai/rnj-1-instruct": { + "id": "essentialai/rnj-1-instruct", + "family": "rnj", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + } + }, + "deepseek-ai/deepseek-v3-1": { + "id": "deepseek-ai/DeepSeek-V3-1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-tput": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-tput", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3-coder-next-fp8": { + "id": "Qwen/Qwen3-Coder-Next-FP8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "minimaxai/chat-completion/models/minimax-m2_5-high-throughput": { + "id": "minimaxai/chat-completion/models/MiniMax-M2_5-high-throughput", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "arcee_ai/afm/models/trinity-mini": { + "id": "arcee_ai/AFM/models/trinity-mini", + "family": "trinity-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "deepseek-ai/deepseek-ocr/models/deepseek-ocr": { + "id": "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "clarifai/main/models/mm-poly-8b": { + "id": "clarifai/main/models/mm-poly-8b", + "family": "mm-poly", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "qwen/qwencoder/models/qwen3-coder-30b-a3b-instruct": { + "id": "qwen/qwenCoder/models/Qwen3-Coder-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwenlm/models/qwen3-30b-a3b-instruct-2507": { + "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwenlm/models/qwen3-30b-a3b-thinking-2507": { + "id": "qwen/qwenLM/models/Qwen3-30B-A3B-Thinking-2507", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "mistralai/completion/models/ministral-3-14b-reasoning-2512": { + "id": "mistralai/completion/models/Ministral-3-14B-Reasoning-2512", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "mistralai/completion/models/ministral-3-3b-reasoning-2512": { + "id": "mistralai/completion/models/Ministral-3-3B-Reasoning-2512", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "openai/chat-completion/models/gpt-oss-120b-high-throughput": { + "id": "openai/chat-completion/models/gpt-oss-120b-high-throughput", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "openai/chat-completion/models/gpt-oss-20b": { + "id": "openai/chat-completion/models/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "baai/bge-reranker-v2-m3": { + "id": "BAAI/bge-reranker-v2-m3", + "family": "bge", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "intfloat/multilingual-e5-large": { + "id": "intfloat/multilingual-e5-large", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 1024 + } + }, + "mistralai/mistral-small-3.2-24b-instruct-2506": { + "id": "mistralai/Mistral-Small-3.2-24B-Instruct-2506", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "lucidquery-nexus-coder": { + "id": "lucidquery-nexus-coder", + "family": "lucid", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 250000, + "output": 60000 + } + }, + "lucidnova-rf1-100b": { + "id": "lucidnova-rf1-100b", + "family": "nova", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 120000, + "output": 8000 + } + }, + "glm-4.6v-flash": { + "id": "glm-4.6v-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "deepseek-reasoner": { + "id": "deepseek-reasoner", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 65536, + "input": 64000 + } + }, + "deepseek-chat": { + "id": "deepseek-chat", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + } + }, + "qwen/qwen3-30b-a3b-2507": { + "id": "qwen/qwen3-30b-a3b-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "qwen/qwen3-coder-30b": { + "id": "qwen/qwen3-coder-30b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "prime-intellect/intellect-3": { + "id": "prime-intellect/intellect-3", + "family": "intellect", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "nvidia/nemotron-nano-9b-v2:free": { + "id": "nvidia/nemotron-nano-9b-v2:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nvidia/nemotron-nano-12b-v2-vl:free": { + "id": "nvidia/nemotron-nano-12b-v2-vl:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nvidia/nemotron-3-nano-30b-a3b:free": { + "id": "nvidia/nemotron-3-nano-30b-a3b:free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "nvidia/nemotron-nano-9b-v2": { + "id": "nvidia/nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "nvidia/nemotron-3-super-120b-a12b-free": { + "id": "nvidia/nemotron-3-super-120b-a12b-free", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "arcee-ai/trinity-large-preview:free": { + "id": "arcee-ai/trinity-large-preview:free", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 26200 + } + }, + "arcee-ai/trinity-mini:free": { + "id": "arcee-ai/trinity-mini:free", + "family": "trinity-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "liquid/lfm-2.5-1.2b-thinking:free": { + "id": "liquid/lfm-2.5-1.2b-thinking:free", + "family": "liquid", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "liquid/lfm-2.5-1.2b-instruct:free": { + "id": "liquid/lfm-2.5-1.2b-instruct:free", + "family": "liquid", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "inception/mercury-2": { + "id": "inception/mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 50000 + } + }, + "inception/mercury": { + "id": "inception/mercury", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "inception/mercury-coder": { + "id": "inception/mercury-coder", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "sourceful/riverflow-v2-fast-preview": { + "id": "sourceful/riverflow-v2-fast-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sourceful/riverflow-v2-max-preview": { + "id": "sourceful/riverflow-v2-max-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sourceful/riverflow-v2-standard-preview": { + "id": "sourceful/riverflow-v2-standard-preview", + "family": "sourceful", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "stepfun/step-3.5-flash:free": { + "id": "stepfun/step-3.5-flash:free", + "family": "step", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "cognitivecomputations/dolphin-mistral-24b-venice-edition:free": { + "id": "cognitivecomputations/dolphin-mistral-24b-venice-edition:free", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "deepseek/deepseek-v3.1-terminus:exacto": { + "id": "deepseek/deepseek-v3.1-terminus:exacto", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek/deepseek-v3.2-speciale": { + "id": "deepseek/deepseek-v3.2-speciale", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163000, + "output": 65536, + "input": 163000 + } + }, + "deepseek/deepseek-chat-v3.1": { + "id": "deepseek/deepseek-chat-v3.1", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 7168 + } + }, + "deepseek/deepseek-chat-v3-0324": { + "id": "deepseek/deepseek-chat-v3-0324", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "openrouter/free": { + "id": "openrouter/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32768 + } + }, + "moonshotai/kimi-k2-0905:exacto": { + "id": "moonshotai/kimi-k2-0905:exacto", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "moonshotai/kimi-k2:free": { + "id": "moonshotai/kimi-k2:free", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32800, + "output": 32800 + } + }, + "google/gemini-2.5-flash-lite-preview-09-2025": { + "id": "google/gemini-2.5-flash-lite-preview-09-2025", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-3.1-pro-preview-customtools": { + "id": "google/gemini-3.1-pro-preview-customtools", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-pro-preview-06-05": { + "id": "google/gemini-2.5-pro-preview-06-05", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-3n-e4b-it:free": { + "id": "google/gemma-3n-e4b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "google/gemini-2.5-flash-preview-09-2025": { + "id": "google/gemini-2.5-flash-preview-09-2025", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-pro-preview-05-06": { + "id": "google/gemini-2.5-pro-preview-05-06", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65535 + } + }, + "google/gemma-3n-e2b-it:free": { + "id": "google/gemma-3n-e2b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "google/gemini-2.0-flash-001": { + "id": "google/gemini-2.0-flash-001", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemma-3-12b-it:free": { + "id": "google/gemma-3-12b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "google/gemma-2-9b-it": { + "id": "google/gemma-2-9b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1639 + } + }, + "google/gemma-3-4b-it:free": { + "id": "google/gemma-3-4b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "google/gemma-3-4b-it": { + "id": "google/gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 19200 + } + }, + "google/gemma-3-27b-it:free": { + "id": "google/gemma-3-27b-it:free", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "z-ai/glm-4.6:exacto": { + "id": "z-ai/glm-4.6:exacto", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "z-ai/glm-4.7-flash": { + "id": "z-ai/glm-4.7-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 40551 + } + }, + "z-ai/glm-4.5-air:free": { + "id": "z-ai/glm-4.5-air:free", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 96000 + } + }, + "z-ai/glm-4.5v": { + "id": "z-ai/glm-4.5v", + "family": "glmv", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 96000, + "input": 64000 + } + }, + "qwen/qwen3-coder:free": { + "id": "qwen/qwen3-coder:free", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "qwen/qwen3-coder-flash": { + "id": "qwen/qwen3-coder-flash", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3-coder:exacto": { + "id": "qwen/qwen3-coder:exacto", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen-2.5-coder-32b-instruct": { + "id": "qwen/qwen-2.5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen3.5-plus-02-15": { + "id": "qwen/qwen3.5-plus-02-15", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3-235b-a22b-07-25": { + "id": "qwen/qwen3-235b-a22b-07-25", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "qwen/qwen3-next-80b-a3b-instruct:free": { + "id": "qwen/qwen3-next-80b-a3b-instruct:free", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3-4b:free": { + "id": "qwen/qwen3-4b:free", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "x-ai/grok-3": { + "id": "x-ai/grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-3-mini-beta": { + "id": "x-ai/grok-3-mini-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-3-mini": { + "id": "x-ai/grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "x-ai/grok-4.20-multi-agent-beta": { + "id": "x-ai/grok-4.20-multi-agent-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 32768 + } + }, + "x-ai/grok-4.20-beta": { + "id": "x-ai/grok-4.20-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 32768 + } + }, + "x-ai/grok-3-beta": { + "id": "x-ai/grok-3-beta", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "meta-llama/llama-3.3-70b-instruct:free": { + "id": "meta-llama/llama-3.3-70b-instruct:free", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "meta-llama/llama-3.2-11b-vision-instruct": { + "id": "meta-llama/llama-3.2-11b-vision-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta-llama/llama-3.2-3b-instruct:free": { + "id": "meta-llama/llama-3.2-3b-instruct:free", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/devstral-medium-2507": { + "id": "mistralai/devstral-medium-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/mistral-medium-3": { + "id": "mistralai/mistral-medium-3", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768, + "input": 131072 + } + }, + "mistralai/codestral-2508": { + "id": "mistralai/codestral-2508", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768, + "input": 256000 + } + }, + "mistralai/mistral-small-3.1-24b-instruct": { + "id": "mistralai/mistral-small-3.1-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 131072 + } + }, + "mistralai/devstral-2512": { + "id": "mistralai/devstral-2512", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "mistralai/mistral-small-3.2-24b-instruct": { + "id": "mistralai/mistral-small-3.2-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/devstral-small-2507": { + "id": "mistralai/devstral-small-2507", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/mistral-medium-3.1": { + "id": "mistralai/mistral-medium-3.1", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768, + "input": 131072 + } + }, + "openai/gpt-oss-120b:exacto": { + "id": "openai/gpt-oss-120b:exacto", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/gpt-5.2-chat": { + "id": "openai/gpt-5.2-chat", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 16384, + "input": 400000 + } + }, + "openai/gpt-5-image": { + "id": "openai/gpt-5-image", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai/gpt-oss-20b:free": { + "id": "openai/gpt-oss-20b:free", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/gpt-oss-safeguard-20b": { + "id": "openai/gpt-oss-safeguard-20b", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "openai/gpt-oss-120b:free": { + "id": "openai/gpt-oss-120b:free", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "minimax/minimax-m1": { + "id": "minimax/minimax-m1", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 40000 + } + }, + "minimax/minimax-01": { + "id": "minimax/minimax-01", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000192, + "output": 16384, + "input": 1000192 + } + }, + "bytedance-seed/seedream-4.5": { + "id": "bytedance-seed/seedream-4.5", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "black-forest-labs/flux.2-pro": { + "id": "black-forest-labs/flux.2-pro", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 46864, + "output": 46864 + } + }, + "black-forest-labs/flux.2-flex": { + "id": "black-forest-labs/flux.2-flex", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 67344, + "output": 67344 + } + }, + "black-forest-labs/flux.2-max": { + "id": "black-forest-labs/flux.2-max", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 46864, + "output": 46864 + } + }, + "black-forest-labs/flux.2-klein-4b": { + "id": "black-forest-labs/flux.2-klein-4b", + "family": "flux", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "nousresearch/hermes-3-llama-3.1-405b:free": { + "id": "nousresearch/hermes-3-llama-3.1-405b:free", + "family": "hermes", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "ai21-labs/ai21-jamba-1.5-mini": { + "id": "ai21-labs/ai21-jamba-1.5-mini", + "family": "jamba", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "ai21-labs/ai21-jamba-1.5-large": { + "id": "ai21-labs/ai21-jamba-1.5-large", + "family": "jamba", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "microsoft/mai-ds-r1": { + "id": "microsoft/mai-ds-r1", + "family": "mai", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "microsoft/phi-3.5-mini-instruct": { + "id": "microsoft/phi-3.5-mini-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-4": { + "id": "microsoft/phi-4", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "microsoft/phi-3-mini-4k-instruct": { + "id": "microsoft/phi-3-mini-4k-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 1024 + } + }, + "microsoft/phi-4-mini-reasoning": { + "id": "microsoft/phi-4-mini-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-3-mini-128k-instruct": { + "id": "microsoft/phi-3-mini-128k-instruct", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "microsoft/phi-4-reasoning": { + "id": "microsoft/phi-4-reasoning", + "family": "phi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "core42/jais-30b-chat": { + "id": "core42/jais-30b-chat", + "family": "jais", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "mistral-ai/ministral-3b": { + "id": "mistral-ai/ministral-3b", + "family": "ministral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral-ai/mistral-medium-2505": { + "id": "mistral-ai/mistral-medium-2505", + "family": "mistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/mistral-nemo": { + "id": "mistral-ai/mistral-nemo", + "family": "mistral-nemo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistral-ai/mistral-large-2411": { + "id": "mistral-ai/mistral-large-2411", + "family": "mistral-large", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/mistral-small-2503": { + "id": "mistral-ai/mistral-small-2503", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "mistral-ai/codestral-2501": { + "id": "mistral-ai/codestral-2501", + "family": "codestral", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "deepseek/deepseek-r1": { + "id": "deepseek/deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "meta/llama-3.2-90b-vision-instruct": { + "id": "meta/llama-3.2-90b-vision-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/meta-llama-3.1-405b-instruct": { + "id": "meta/meta-llama-3.1-405b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/meta-llama-3-8b-instruct": { + "id": "meta/meta-llama-3-8b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "meta/meta-llama-3-70b-instruct": { + "id": "meta/meta-llama-3-70b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "meta/meta-llama-3.1-70b-instruct": { + "id": "meta/meta-llama-3.1-70b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/meta-llama-3.1-8b-instruct": { + "id": "meta/meta-llama-3.1-8b-instruct", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "meta/llama-4-maverick-17b-128e-instruct-fp8": { + "id": "meta/llama-4-maverick-17b-128e-instruct-fp8", + "family": "llama", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/o1-preview": { + "id": "openai/o1-preview", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768, + "input": 128000 + } + }, + "openai/o1-mini": { + "id": "openai/o1-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 65536 + } + }, + "cohere/cohere-command-a": { + "id": "cohere/cohere-command-a", + "family": "command-a", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r-plus-08-2024": { + "id": "cohere/cohere-command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r": { + "id": "cohere/cohere-command-r", + "family": "command-r", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r-08-2024": { + "id": "cohere/cohere-command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "cohere/cohere-command-r-plus": { + "id": "cohere/cohere-command-r-plus", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen-max-latest": { + "id": "qwen-max-latest", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3-max-2025-09-23": { + "id": "qwen3-max-2025-09-23", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 258048, + "output": 65536 + } + }, + "gemini-2.5-flash-lite-preview-09-2025": { + "id": "gemini-2.5-flash-lite-preview-09-2025", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + }, + "family": "gemini-flash-lite" + }, + "claude-opus-4-1-20250805-thinking": { + "id": "claude-opus-4-1-20250805-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "gemini-2.5-flash-preview-09-2025": { + "id": "gemini-2.5-flash-preview-09-2025", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + }, + "family": "gemini-flash" + }, + "grok-4-1-fast-reasoning": { + "id": "grok-4-1-fast-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + }, + "family": "grok" + }, + "kimi-k2-0905-preview": { + "id": "kimi-k2-0905-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "kimi" + }, + "claude-sonnet-4-5-20250929-thinking": { + "id": "claude-sonnet-4-5-20250929-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000, + "input": 1000000 + } + }, + "doubao-seed-1-6-vision-250815": { + "id": "doubao-seed-1-6-vision-250815", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "doubao-seed-1-6-thinking-250715": { + "id": "doubao-seed-1-6-thinking-250715", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16000 + } + }, + "doubao-seed-1-8-251215": { + "id": "doubao-seed-1-8-251215", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + } + }, + "ministral-14b-2512": { + "id": "ministral-14b-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "gemini-2.5-flash-nothink": { + "id": "gemini-2.5-flash-nothink", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "claude-opus-4-5-20251101-thinking": { + "id": "claude-opus-4-5-20251101-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "gemini-3-pro-image-preview": { + "id": "gemini-3-pro-image-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "gpt-5-thinking": { + "id": "gpt-5-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "deepseek-v3.2-thinking": { + "id": "deepseek-v3.2-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "chatgpt-4o-latest": { + "id": "chatgpt-4o-latest", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "kimi-k2-thinking-turbo": { + "id": "kimi-k2-thinking-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "kimi-thinking" + }, + "doubao-seed-code-preview-251028": { + "id": "doubao-seed-code-preview-251028", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "grok-4.1": { + "id": "grok-4.1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-sonnet-4.6": { + "id": "claude-sonnet-4.6", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 128000, + "output": 32000 + } + }, + "claude-haiku-4.5": { + "id": "claude-haiku-4.5", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + } + }, + "claude-opus-4.5": { + "id": "claude-opus-4.5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "input": 128000, + "output": 32000 + } + }, + "claude-sonnet-4.5": { + "id": "claude-sonnet-4.5", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 32000 + } + }, + "claude-opus-4.6": { + "id": "claude-opus-4.6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 144000, + "input": 128000, + "output": 64000 + } + }, + "claude-opus-41": { + "id": "claude-opus-41", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "output": 16000 + } + }, + "kimi-k2-0711-preview": { + "id": "kimi-k2-0711-preview", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "gemini-embedding-001": { + "id": "gemini-embedding-001", + "family": "gemini", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2048, + "output": 3072 + } + }, + "gemini-3.1-pro-preview-customtools": { + "id": "gemini-3.1-pro-preview-customtools", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "gemini-2.5-pro-preview-06-05": { + "id": "gemini-2.5-pro-preview-06-05", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "gemini-2.5-flash-preview-04-17": { + "id": "gemini-2.5-flash-preview-04-17", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "gemini-2.5-pro-preview-05-06": { + "id": "gemini-2.5-pro-preview-05-06", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "gemini-2.5-flash-preview-05-20": { + "id": "gemini-2.5-flash-preview-05-20", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048000, + "output": 65536, + "input": 1048000 + } + }, + "gemini-flash-latest": { + "id": "gemini-flash-latest", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "gemini-2.5-flash-lite-preview-06-17": { + "id": "gemini-2.5-flash-lite-preview-06-17", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "output": 65536, + "input": 1048756 + } + }, + "gemini-flash-lite-latest": { + "id": "gemini-flash-lite-latest", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "zai-org/glm-5-maas": { + "id": "zai-org/glm-5-maas", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "zai-org/glm-4.7-maas": { + "id": "zai-org/glm-4.7-maas", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "deepseek-ai/deepseek-v3.1-maas": { + "id": "deepseek-ai/deepseek-v3.1-maas", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-maas": { + "id": "qwen/qwen3-235b-a22b-instruct-2507-maas", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "meta/llama-4-maverick-17b-128e-instruct-maas": { + "id": "meta/llama-4-maverick-17b-128e-instruct-maas", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 524288, + "output": 8192 + } + }, + "meta/llama-3.3-70b-instruct-maas": { + "id": "meta/llama-3.3-70b-instruct-maas", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "openai/gpt-oss-20b-maas": { + "id": "openai/gpt-oss-20b-maas", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "openai/gpt-oss-120b-maas": { + "id": "openai/gpt-oss-120b-maas", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "gemma-3-27b": { + "id": "gemma-3-27b", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "qwen3-embedding-4b": { + "id": "qwen3-embedding-4b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 2560 + } + }, + "qwen3-coder-30b-a3b": { + "id": "qwen3-coder-30b-a3b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "gemini-3.1-flash-image-preview": { + "id": "gemini-3.1-flash-image-preview", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "gemini-live-2.5-flash": { + "id": "gemini-live-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "gemini-live-2.5-flash-preview-native-audio": { + "id": "gemini-live-2.5-flash-preview-native-audio", + "family": "gemini-flash", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "audio", + "video" + ], + "output": [ + "text", + "audio" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "gemini-2.5-flash-preview-tts": { + "id": "gemini-2.5-flash-preview-tts", + "family": "gemini-flash", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "gemini-2.5-pro-preview-tts": { + "id": "gemini-2.5-pro-preview-tts", + "family": "gemini-flash", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "gemini-2.5-flash-image-preview": { + "id": "gemini-2.5-flash-image-preview", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "gemini-1.5-flash-8b": { + "id": "gemini-1.5-flash-8b", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "gemini-1.5-flash": { + "id": "gemini-1.5-flash", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "gemini-1.5-pro": { + "id": "gemini-1.5-pro", + "family": "gemini-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192 + } + }, + "anthropic--claude-4.5-opus": { + "id": "anthropic--claude-4.5-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4-sonnet": { + "id": "anthropic--claude-4-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-4.5-sonnet": { + "id": "anthropic--claude-4.5-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-3-sonnet": { + "id": "anthropic--claude-3-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic--claude-3.7-sonnet": { + "id": "anthropic--claude-3.7-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "sonar": { + "id": "sonar", + "family": "sonar", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 128000, + "input": 127000 + } + }, + "anthropic--claude-3.5-sonnet": { + "id": "anthropic--claude-3.5-sonnet", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "sonar-deep-research": { + "id": "sonar-deep-research", + "family": "sonar-deep-research", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 60000, + "output": 128000, + "input": 60000 + } + }, + "anthropic--claude-4.6-sonnet": { + "id": "anthropic--claude-4.6-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "anthropic--claude-4.5-haiku": { + "id": "anthropic--claude-4.5-haiku", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "anthropic--claude-3-opus": { + "id": "anthropic--claude-3-opus", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "sonar-pro": { + "id": "sonar-pro", + "family": "sonar-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000, + "input": 200000 + } + }, + "anthropic--claude-3-haiku": { + "id": "anthropic--claude-3-haiku", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "anthropic--claude-4.6-opus": { + "id": "anthropic--claude-4.6-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic--claude-4-opus": { + "id": "anthropic--claude-4-opus", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "google-gemma-3-27b-it": { + "id": "google-gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "openai-gpt-4o-2024-11-20": { + "id": "openai-gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-opus-45": { + "id": "claude-opus-45", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 49500 + } + }, + "zai-org-glm-5": { + "id": "zai-org-glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32000 + } + }, + "zai-org-glm-4.7": { + "id": "zai-org-glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "zai-org-glm-4.6": { + "id": "zai-org-glm-4.6", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "openai-gpt-53-codex": { + "id": "openai-gpt-53-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "kimi-k2-5": { + "id": "kimi-k2-5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "mistral-small-3-2-24b-instruct": { + "id": "mistral-small-3-2-24b-instruct", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "mistral-31-24b": { + "id": "mistral-31-24b", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "grok-4-20-multi-agent-beta": { + "id": "grok-4-20-multi-agent-beta", + "family": "grok-beta", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "openai-gpt-54-pro": { + "id": "openai-gpt-54-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "qwen3-4b": { + "id": "qwen3-4b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "grok-4-20-beta": { + "id": "grok-4-20-beta", + "family": "grok-beta", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "olafangensan-glm-4.7-flash-heretic": { + "id": "olafangensan-glm-4.7-flash-heretic", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 24000 + } + }, + "minimax-m25": { + "id": "minimax-m25", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32768 + } + }, + "zai-org-glm-4.7-flash": { + "id": "zai-org-glm-4.7-flash", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-coder-480b-a35b-instruct-turbo": { + "id": "qwen3-coder-480b-a35b-instruct-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "openai-gpt-oss-120b": { + "id": "openai-gpt-oss-120b", + "family": "gpt-oss", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-41-fast": { + "id": "grok-41-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 30000 + } + }, + "openai-gpt-52": { + "id": "openai-gpt-52", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "openai-gpt-54": { + "id": "openai-gpt-54", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 131072 + } + }, + "gemini-3-1-pro-preview": { + "id": "gemini-3-1-pro-preview", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "openai-gpt-4o-mini-2024-07-18": { + "id": "openai-gpt-4o-mini-2024-07-18", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "llama-3.3-70b": { + "id": "llama-3.3-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "qwen3-next-80b": { + "id": "qwen3-next-80b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "hermes-3-llama-3.1-405b": { + "id": "hermes-3-llama-3.1-405b", + "family": "hermes", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-5-9b": { + "id": "qwen3-5-9b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "minimax-m21": { + "id": "minimax-m21", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32768 + } + }, + "qwen3-5-35b-a3b": { + "id": "qwen3-5-35b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "llama-3.2-3b": { + "id": "llama-3.2-3b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "venice-uncensored": { + "id": "venice-uncensored", + "family": "venice", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + } + }, + "nvidia-nemotron-3-nano-30b-a3b": { + "id": "nvidia-nemotron-3-nano-30b-a3b", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai-gpt-52-codex": { + "id": "openai-gpt-52-codex", + "family": "gpt-codex", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "minimax-m27": { + "id": "minimax-m27", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 32768 + } + }, + "venice-uncensored-role-play": { + "id": "venice-uncensored-role-play", + "family": "venice", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "claude-sonnet-45": { + "id": "claude-sonnet-45", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 49500 + } + }, + "nova-2-lite-v1": { + "id": "nova-2-lite-v1", + "family": "nova-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "nova-2-pro-v1": { + "id": "nova-2-pro-v1", + "family": "nova-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "glm-4.7-flashx": { + "id": "glm-4.7-flashx", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "public/deepseek-v3": { + "id": "public/deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "public/deepseek-r1": { + "id": "public/deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "public/minimax-m25": { + "id": "public/minimax-m25", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "gpt-5-4": { + "id": "gpt-5-4", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 272000, + "output": 128000 + } + }, + "deepseek-v3-2": { + "id": "deepseek-v3-2", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "minimax-m2-5": { + "id": "minimax-m2-5", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 192000, + "output": 8192 + } + }, + "gpt-5-3-codex": { + "id": "gpt-5-3-codex", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "meta-llama-3_3-70b-instruct": { + "id": "meta-llama-3_3-70b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistral-7b-instruct-v0.3": { + "id": "mistral-7b-instruct-v0.3", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "qwen2.5-coder-32b-instruct": { + "id": "qwen2.5-coder-32b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mixtral-8x7b-instruct-v0.1": { + "id": "mixtral-8x7b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "neuralmagic/meta-llama-3.1-8b-instruct-fp8": { + "id": "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "neuralmagic/mistral-nemo-instruct-2407-fp8": { + "id": "neuralmagic/Mistral-Nemo-Instruct-2407-FP8", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "qwen/qwen3-vl-embedding-8b": { + "id": "Qwen/Qwen3-VL-Embedding-8B", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "qwen/qwen3-vl-235b-a22b-instruct-fp8": { + "id": "Qwen/Qwen3-VL-235B-A22B-Instruct-FP8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 218000, + "output": 8192 + } + }, + "cortecs/llama-3.3-70b-instruct-fp8-dynamic": { + "id": "cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "speakleash/bielik-11b-v2.6-instruct": { + "id": "speakleash/Bielik-11B-v2.6-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "speakleash/bielik-11b-v3.0-instruct": { + "id": "speakleash/Bielik-11B-v3.0-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "anthropic/claude-3-7-sonnet": { + "id": "anthropic/claude-3-7-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "xai/grok-4-fast": { + "id": "xai/grok-4-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 64000 + } + }, + "pro/zai-org/glm-4.7": { + "id": "Pro/zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "pro/zai-org/glm-5": { + "id": "Pro/zai-org/GLM-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 205000 + } + }, + "pro/minimaxai/minimax-m2.5": { + "id": "Pro/MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 192000, + "output": 131000 + } + }, + "pro/minimaxai/minimax-m2.1": { + "id": "Pro/MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 197000, + "output": 131000 + } + }, + "pro/deepseek-ai/deepseek-r1": { + "id": "Pro/deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-v3.2": { + "id": "Pro/deepseek-ai/DeepSeek-V3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-v3": { + "id": "Pro/deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/deepseek-ai/deepseek-v3.1-terminus": { + "id": "Pro/deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "output": 164000 + } + }, + "pro/moonshotai/kimi-k2-instruct-0905": { + "id": "Pro/moonshotai/Kimi-K2-Instruct-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "pro/moonshotai/kimi-k2.5": { + "id": "Pro/moonshotai/Kimi-K2.5", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "pro/moonshotai/kimi-k2-thinking": { + "id": "Pro/moonshotai/Kimi-K2-Thinking", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "paddlepaddle/paddleocr-vl-1.5": { + "id": "PaddlePaddle/PaddleOCR-VL-1.5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "kwaipilot/kat-dev": { + "id": "Kwaipilot/KAT-Dev", + "family": "kat-coder", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "deepseek-ai/deepseek-ocr": { + "id": "deepseek-ai/DeepSeek-OCR", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "ascend-tribe/pangu-pro-moe": { + "id": "ascend-tribe/pangu-pro-moe", + "family": "pangu", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "qwen/qwen3.5-9b": { + "id": "qwen/qwen3.5-9b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768 + } + }, + "qwen/qwen3.5-122b-a10b": { + "id": "qwen/qwen3.5-122b-a10b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3.5-35b-a3b": { + "id": "qwen/qwen3.5-35b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3.5-4b": { + "id": "Qwen/Qwen3.5-4B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3.5-27b": { + "id": "qwen/qwen3.5-27b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "gpt-5-chat-latest": { + "id": "gpt-5-chat-latest", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "llama-4-scout": { + "id": "llama-4-scout", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "codex-mini-latest": { + "id": "codex-mini-latest", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "qwen2.5-coder-7b-fast": { + "id": "qwen2.5-coder-7b-fast", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "sonar-reasoning-pro": { + "id": "sonar-reasoning-pro", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 128000, + "input": 127000 + } + }, + "llama-3.1-8b-instruct-turbo": { + "id": "llama-3.1-8b-instruct-turbo", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "ernie-4.5-21b-a3b-thinking": { + "id": "ernie-4.5-21b-a3b-thinking", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "llama-prompt-guard-2-22m": { + "id": "llama-prompt-guard-2-22m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 2 + } + }, + "gpt-4.1-mini-2025-04-14": { + "id": "gpt-4.1-mini-2025-04-14", + "family": "gpt-mini", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1047576, + "output": 32768 + } + }, + "llama-guard-4": { + "id": "llama-guard-4", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 1024 + } + }, + "sonar-reasoning": { + "id": "sonar-reasoning", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 4096 + } + }, + "deepseek-v3.1-terminus": { + "id": "deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-3.5-sonnet-v2": { + "id": "claude-3.5-sonnet-v2", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "mistral-small": { + "id": "mistral-small", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "qwen3-vl-235b-a22b-instruct": { + "id": "qwen3-vl-235b-a22b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "qwen3-235b-a22b-thinking": { + "id": "qwen3-235b-a22b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 81920 + } + }, + "claude-3-haiku-20240307": { + "id": "claude-3-haiku-20240307", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "kimi-k2-0711": { + "id": "kimi-k2-0711", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "llama-4-maverick": { + "id": "llama-4-maverick", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "deepseek-tng-r1t2-chimera": { + "id": "deepseek-tng-r1t2-chimera", + "family": "deepseek-thinking", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 130000, + "output": 163840 + } + }, + "claude-opus-4": { + "id": "claude-opus-4", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "llama-prompt-guard-2-86m": { + "id": "llama-prompt-guard-2-86m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 2 + } + }, + "gemma-3-12b-it": { + "id": "gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "hermes-2-pro-llama-3-8b": { + "id": "hermes-2-pro-llama-3-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "zai/glm-5": { + "id": "zai/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "output": 131072 + } + }, + "zai/glm-4.7-flashx": { + "id": "zai/glm-4.7-flashx", + "family": "glm-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "zai/glm-4.5-air": { + "id": "zai/glm-4.5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 96000 + } + }, + "zai/glm-4.5": { + "id": "zai/glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "zai/glm-4.7-flash": { + "id": "zai/glm-4.7-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131000 + } + }, + "zai/glm-4.6": { + "id": "zai/glm-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 96000 + } + }, + "zai/glm-4.7": { + "id": "zai/glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 120000 + } + }, + "zai/glm-4.6v-flash": { + "id": "zai/glm-4.6v-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 24000 + } + }, + "zai/glm-5-turbo": { + "id": "zai/glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "output": 131100 + } + }, + "zai/glm-4.5v": { + "id": "zai/glm-4.5v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "zai/glm-4.6v": { + "id": "zai/glm-4.6v", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 24000 + } + }, + "nvidia/nemotron-nano-12b-v2-vl": { + "id": "nvidia/nemotron-nano-12b-v2-vl", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "arcee-ai/trinity-large-preview": { + "id": "arcee-ai/trinity-large-preview", + "family": "trinity", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "arcee-ai/trinity-mini": { + "id": "arcee-ai/trinity-mini", + "family": "trinity-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192, + "input": 131072 + } + }, + "inception/mercury-coder-small": { + "id": "inception/mercury-coder-small", + "family": "mercury", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 16384 + } + }, + "voyage/voyage-3-large": { + "id": "voyage/voyage-3-large", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-code-3": { + "id": "voyage/voyage-code-3", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-law-2": { + "id": "voyage/voyage-law-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-finance-2": { + "id": "voyage/voyage-finance-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-code-2": { + "id": "voyage/voyage-code-2", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-4-lite": { + "id": "voyage/voyage-4-lite", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "voyage/voyage-3.5-lite": { + "id": "voyage/voyage-3.5-lite", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-4-large": { + "id": "voyage/voyage-4-large", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "voyage/voyage-3.5": { + "id": "voyage/voyage-3.5", + "family": "voyage", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "voyage/voyage-4": { + "id": "voyage/voyage-4", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "amazon/nova-2-lite": { + "id": "amazon/nova-2-lite", + "family": "nova", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "amazon/titan-embed-text-v2": { + "id": "amazon/titan-embed-text-v2", + "family": "titan-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "amazon/nova-lite": { + "id": "amazon/nova-lite", + "family": "nova-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "amazon/nova-pro": { + "id": "amazon/nova-pro", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 8192 + } + }, + "amazon/nova-micro": { + "id": "amazon/nova-micro", + "family": "nova-micro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "alibaba/qwen-3-235b": { + "id": "alibaba/qwen-3-235b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-max-preview": { + "id": "alibaba/qwen3-max-preview", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3-next-80b-a3b-thinking": { + "id": "alibaba/qwen3-next-80b-a3b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "alibaba/qwen3-max-thinking": { + "id": "alibaba/qwen3-max-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "alibaba/qwen3-vl-instruct": { + "id": "alibaba/qwen3-vl-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 129024 + } + }, + "alibaba/qwen3-embedding-8b": { + "id": "alibaba/qwen3-embedding-8b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen3-coder-next": { + "id": "alibaba/qwen3-coder-next", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "alibaba/qwen3-coder": { + "id": "alibaba/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "alibaba/qwen-3-30b": { + "id": "alibaba/qwen-3-30b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-embedding-0.6b": { + "id": "alibaba/qwen3-embedding-0.6b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen-3-14b": { + "id": "alibaba/qwen-3-14b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-235b-a22b-thinking": { + "id": "alibaba/qwen3-235b-a22b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + } + }, + "alibaba/qwen3-vl-thinking": { + "id": "alibaba/qwen3-vl-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 129024 + } + }, + "alibaba/qwen3.5-flash": { + "id": "alibaba/qwen3.5-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen3-next-80b-a3b-instruct": { + "id": "alibaba/qwen3-next-80b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen3.5-plus": { + "id": "alibaba/qwen3.5-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "alibaba/qwen3-max": { + "id": "alibaba/qwen3-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "alibaba/qwen-3-32b": { + "id": "alibaba/qwen-3-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 16384 + } + }, + "alibaba/qwen3-coder-plus": { + "id": "alibaba/qwen3-coder-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "alibaba/qwen3-embedding-4b": { + "id": "alibaba/qwen3-embedding-4b", + "family": "qwen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alibaba/qwen3-coder-30b-a3b": { + "id": "alibaba/qwen3-coder-30b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "output": 32768 + } + }, + "bfl/flux-pro-1.0-fill": { + "id": "bfl/flux-pro-1.0-fill", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-pro-1.1": { + "id": "bfl/flux-pro-1.1", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-kontext-max": { + "id": "bfl/flux-kontext-max", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-kontext-pro": { + "id": "bfl/flux-kontext-pro", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "bfl/flux-pro-1.1-ultra": { + "id": "bfl/flux-pro-1.1-ultra", + "family": "flux", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "mistral/codestral-embed": { + "id": "mistral/codestral-embed", + "family": "codestral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "mistral/devstral-small-2": { + "id": "mistral/devstral-small-2", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/devstral-2": { + "id": "mistral/devstral-2", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/mistral-large-3": { + "id": "mistral/mistral-large-3", + "family": "mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/mistral-embed": { + "id": "mistral/mistral-embed", + "family": "mistral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "mistral/ministral-14b": { + "id": "mistral/ministral-14b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "mistral/mistral-nemo": { + "id": "mistral/mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 60288, + "output": 16000 + } + }, + "mistral/mistral-medium": { + "id": "mistral/mistral-medium", + "family": "mistral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "mistral/devstral-small": { + "id": "mistral/devstral-small", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "mistral/codestral": { + "id": "mistral/codestral", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "mistral/mixtral-8x22b-instruct": { + "id": "mistral/mixtral-8x22b-instruct", + "family": "mixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "mistral/mistral-small": { + "id": "mistral/mistral-small", + "family": "mistral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral/ministral-8b": { + "id": "mistral/ministral-8b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/pixtral-large": { + "id": "mistral/pixtral-large", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/pixtral-12b": { + "id": "mistral/pixtral-12b", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/magistral-small": { + "id": "mistral/magistral-small", + "family": "magistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/magistral-medium": { + "id": "mistral/magistral-medium", + "family": "magistral-medium", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral/ministral-3b": { + "id": "mistral/ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "kwaipilot/kat-coder-pro-v1": { + "id": "kwaipilot/kat-coder-pro-v1", + "family": "kat-coder", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "deepseek/deepseek-v3": { + "id": "deepseek/deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 16384 + } + }, + "deepseek/deepseek-v3.2-thinking": { + "id": "deepseek/deepseek-v3.2-thinking", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "moonshotai/kimi-k2-turbo": { + "id": "moonshotai/kimi-k2-turbo", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "google/gemini-embedding-001": { + "id": "google/gemini-embedding-001", + "family": "gemini-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/imagen-4.0-fast-generate-001": { + "id": "google/imagen-4.0-fast-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/text-embedding-005": { + "id": "google/text-embedding-005", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/imagen-4.0-ultra-generate-001": { + "id": "google/imagen-4.0-ultra-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "google/gemini-3.1-flash-image-preview": { + "id": "google/gemini-3.1-flash-image-preview", + "family": "gemini", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "google/text-multilingual-embedding-002": { + "id": "google/text-multilingual-embedding-002", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "google/gemini-embedding-2": { + "id": "google/gemini-embedding-2", + "family": "gemini-embedding", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "google/gemini-2.5-flash-image": { + "id": "google/gemini-2.5-flash-image", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "google/gemini-3-pro-image": { + "id": "google/gemini-3-pro-image", + "family": "gemini-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 65536, + "output": 32768 + } + }, + "google/gemini-2.5-flash-image-preview": { + "id": "google/gemini-2.5-flash-image-preview", + "family": "gemini-flash", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "google/imagen-4.0-generate-001": { + "id": "google/imagen-4.0-generate-001", + "family": "imagen", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 480, + "output": 0 + } + }, + "meituan/longcat-flash-thinking": { + "id": "meituan/longcat-flash-thinking", + "family": "longcat", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meituan/longcat-flash-thinking-2601": { + "id": "meituan/longcat-flash-thinking-2601", + "family": "longcat", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "bytedance/seed-1.6": { + "id": "bytedance/seed-1.6", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "bytedance/seed-1.8": { + "id": "bytedance/seed-1.8", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "meta/llama-3.1-8b": { + "id": "meta/llama-3.1-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta/llama-3.2-11b": { + "id": "meta/llama-3.2-11b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.1-70b": { + "id": "meta/llama-3.1-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "meta/llama-3.2-90b": { + "id": "meta/llama-3.2-90b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.2-1b": { + "id": "meta/llama-3.2-1b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-3.2-3b": { + "id": "meta/llama-3.2-3b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "meta/llama-4-maverick": { + "id": "meta/llama-4-maverick", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-3.3-70b": { + "id": "meta/llama-3.3-70b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "meta/llama-4-scout": { + "id": "meta/llama-4-scout", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "vercel/v0-1.5-md": { + "id": "vercel/v0-1.5-md", + "family": "v0", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "vercel/v0-1.0-md": { + "id": "vercel/v0-1.0-md", + "family": "v0", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "openai/text-embedding-ada-002": { + "id": "openai/text-embedding-ada-002", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "openai/gpt-4o-mini-search-preview": { + "id": "openai/gpt-4o-mini-search-preview", + "family": "gpt-mini", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "openai/text-embedding-3-small": { + "id": "openai/text-embedding-3-small", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "openai/text-embedding-3-large": { + "id": "openai/text-embedding-3-large", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 6656, + "output": 1536 + } + }, + "openai/gpt-5.1-thinking": { + "id": "openai/gpt-5.1-thinking", + "family": "gpt", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "openai/codex-mini": { + "id": "openai/codex-mini", + "family": "gpt-codex-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + } + }, + "morph/morph-v3-large": { + "id": "morph/morph-v3-large", + "family": "morph", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "morph/morph-v3-fast": { + "id": "morph/morph-v3-fast", + "family": "morph", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 81920, + "output": 38000 + } + }, + "cohere/embed-v4.0": { + "id": "cohere/embed-v4.0", + "family": "cohere-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1536 + } + }, + "cohere/command-a": { + "id": "cohere/command-a", + "family": "command", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "minimax/minimax-m2.1-lightning": { + "id": "minimax/minimax-m2.1-lightning", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "recraft/recraft-v2": { + "id": "recraft/recraft-v2", + "family": "recraft", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "recraft/recraft-v3": { + "id": "recraft/recraft-v3", + "family": "recraft", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 512, + "output": 0 + } + }, + "perplexity/sonar-reasoning-pro": { + "id": "perplexity/sonar-reasoning-pro", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 25600 + } + }, + "perplexity/sonar-reasoning": { + "id": "perplexity/sonar-reasoning", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + } + }, + "perplexity/sonar-pro": { + "id": "perplexity/sonar-pro", + "family": "sonar-pro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8000 + } + }, + "anthropic/claude-3.5-sonnet-20240620": { + "id": "anthropic/claude-3.5-sonnet-20240620", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "xai/grok-4.20-non-reasoning-beta": { + "id": "xai/grok-4.20-non-reasoning-beta", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-4.20-non-reasoning": { + "id": "xai/grok-4.20-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-imagine-image": { + "id": "xai/grok-imagine-image", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "xai/grok-4.20-reasoning": { + "id": "xai/grok-4.20-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-4.20-reasoning-beta": { + "id": "xai/grok-4.20-reasoning-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-4.20-multi-agent": { + "id": "xai/grok-4.20-multi-agent", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-imagine-image-pro": { + "id": "xai/grok-imagine-image-pro", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "xai/grok-4.20-multi-agent-beta": { + "id": "xai/grok-4.20-multi-agent-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "xai/grok-3-fast": { + "id": "xai/grok-3-fast", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "xai/grok-3-mini-fast": { + "id": "xai/grok-3-mini-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "xai/grok-2-vision": { + "id": "xai/grok-2-vision", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "gpt-4o-2024-05-13": { + "id": "gpt-4o-2024-05-13", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "o3-deep-research": { + "id": "o3-deep-research", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "o4-mini-deep-research": { + "id": "o4-mini-deep-research", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-3.5-turbo": { + "id": "gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 4096 + } + }, + "o1-pro": { + "id": "o1-pro", + "family": "o-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "gpt-5.2-pro": { + "id": "gpt-5.2-pro", + "family": "gpt-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + } + }, + "gpt-4o-2024-08-06": { + "id": "gpt-4o-2024-08-06", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "auto": { + "id": "auto", + "family": "auto", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "morph-v3-fast": { + "id": "morph-v3-fast", + "family": "morph", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 16000 + } + }, + "morph-v3-large": { + "id": "morph-v3-large", + "family": "morph", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + } + }, + "c4ai-aya-expanse-32b": { + "id": "c4ai-aya-expanse-32b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-03-2025": { + "id": "command-a-03-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + } + }, + "command-r7b-arabic-02-2025": { + "id": "command-r7b-arabic-02-2025", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-translate-08-2025": { + "id": "command-a-translate-08-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 8000 + } + }, + "command-r-08-2024": { + "id": "command-r-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-r-plus-08-2024": { + "id": "command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-reasoning-08-2025": { + "id": "command-a-reasoning-08-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192, + "input": 256000 + } + }, + "c4ai-aya-expanse-8b": { + "id": "c4ai-aya-expanse-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 4000 + } + }, + "c4ai-aya-vision-8b": { + "id": "c4ai-aya-vision-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4000 + } + }, + "c4ai-aya-vision-32b": { + "id": "c4ai-aya-vision-32b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4000 + } + }, + "command-r7b-12-2024": { + "id": "command-r7b-12-2024", + "family": "command-r", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "command-a-vision-07-2025": { + "id": "command-a-vision-07-2025", + "family": "command-a", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8000 + } + }, + "v0-1.0-md": { + "id": "v0-1.0-md", + "family": "v0", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 200000 + } + }, + "v0-1.5-md": { + "id": "v0-1.5-md", + "family": "v0", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 200000 + } + }, + "v0-1.5-lg": { + "id": "v0-1.5-lg", + "family": "v0", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000, + "input": 1000000 + } + }, + "llama-3_1-nemotron-ultra-253b-v1": { + "id": "Llama-3_1-Nemotron-Ultra-253B-v1", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 4096 + } + }, + "deepseek-r1-distill-qwen-32b": { + "id": "deepseek-r1-distill-qwen-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "glm-5-fp8": { + "id": "GLM-5-FP8", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202000, + "output": 131072 + } + }, + "nvidia-nemotron-3-super-120b-a12b-nvfp4": { + "id": "NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 260000, + "output": 8192 + } + }, + "nvidia/nemotron-120b-a12b": { + "id": "nvidia/Nemotron-120B-A12B", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32678 + } + }, + "claude-3-5-haiku-latest": { + "id": "claude-3-5-haiku-latest", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-3-5-sonnet-20241022": { + "id": "claude-3-5-sonnet-20241022", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192, + "input": 200000 + } + }, + "claude-3-sonnet-20240229": { + "id": "claude-3-sonnet-20240229", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "claude-sonnet-4-0": { + "id": "claude-sonnet-4-0", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-opus-4-0": { + "id": "claude-opus-4-0", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-3-5-haiku-20241022": { + "id": "claude-3-5-haiku-20241022", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192, + "input": 200000 + } + }, + "claude-3-5-sonnet-20240620": { + "id": "claude-3-5-sonnet-20240620", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192, + "input": 200000 + } + }, + "claude-3-7-sonnet-latest": { + "id": "claude-3-7-sonnet-latest", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-3-opus-20240229": { + "id": "claude-3-opus-20240229", + "family": "claude-opus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "hunyuan-turbos": { + "id": "hunyuan-turbos", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "tc-code-latest": { + "id": "tc-code-latest", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-t1": { + "id": "hunyuan-t1", + "family": "hunyuan", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-2.0-instruct": { + "id": "hunyuan-2.0-instruct", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "hunyuan-2.0-thinking": { + "id": "hunyuan-2.0-thinking", + "family": "hunyuan", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "claude-sonnet-4-5@20250929": { + "id": "claude-sonnet-4-5@20250929", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-opus-4-1@20250805": { + "id": "claude-opus-4-1@20250805", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-3-7-sonnet@20250219": { + "id": "claude-3-7-sonnet@20250219", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-opus-4@20250514": { + "id": "claude-opus-4@20250514", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "claude-opus-4-5@20251101": { + "id": "claude-opus-4-5@20251101", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-3-5-haiku@20241022": { + "id": "claude-3-5-haiku@20241022", + "family": "claude-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-sonnet-4@20250514": { + "id": "claude-sonnet-4@20250514", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-3-5-sonnet@20241022": { + "id": "claude-3-5-sonnet@20241022", + "family": "claude-sonnet", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "claude-opus-4-6@default": { + "id": "claude-opus-4-6@default", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "claude-haiku-4-5@20251001": { + "id": "claude-haiku-4-5@20251001", + "family": "claude-haiku", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "claude-sonnet-4-6@default": { + "id": "claude-sonnet-4-6@default", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "giga-potato-thinking": { + "id": "giga-potato-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "corethink:free": { + "id": "corethink:free", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 78000, + "output": 8192 + } + }, + "morph-warp-grep-v2": { + "id": "morph-warp-grep-v2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "giga-potato": { + "id": "giga-potato", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32000 + } + }, + "allenai/olmo-2-0325-32b-instruct": { + "id": "allenai/olmo-2-0325-32b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "allenai/olmo-3-7b-instruct": { + "id": "allenai/olmo-3-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "allenai/olmo-3-32b-think": { + "id": "allenai/olmo-3-32b-think", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + }, + "family": "allenai" + }, + "allenai/molmo-2-8b": { + "id": "allenai/molmo-2-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 36864, + "output": 36864, + "input": 36864 + }, + "family": "allenai" + }, + "allenai/olmo-3.1-32b-instruct": { + "id": "allenai/olmo-3.1-32b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192, + "input": 65536 + }, + "family": "allenai" + }, + "allenai/olmo-3-7b-think": { + "id": "allenai/olmo-3-7b-think", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "allenai/olmo-3.1-32b-think": { + "id": "allenai/olmo-3.1-32b-think", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192, + "input": 65536 + }, + "family": "allenai" + }, + "nvidia/nemotron-3-super-120b-a12b:free": { + "id": "nvidia/nemotron-3-super-120b-a12b:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "ibm-granite/granite-4.0-h-micro": { + "id": "ibm-granite/granite-4.0-h-micro", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32768 + } + }, + "arcee-ai/coder-large": { + "id": "arcee-ai/coder-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "arcee-ai/virtuoso-large": { + "id": "arcee-ai/virtuoso-large", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 64000 + } + }, + "arcee-ai/maestro-reasoning": { + "id": "arcee-ai/maestro-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "arcee-ai/spotlight": { + "id": "arcee-ai/spotlight", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65537 + } + }, + "alfredpros/codellama-7b-instruct-solidity": { + "id": "alfredpros/codellama-7b-instruct-solidity", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "liquid/lfm-2.2-6b": { + "id": "liquid/lfm-2.2-6b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "liquid/lfm-2-24b-a2b": { + "id": "liquid/lfm-2-24b-a2b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "liquid/lfm2-8b-a1b": { + "id": "liquid/lfm2-8b-a1b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "upstage/solar-pro-3": { + "id": "upstage/solar-pro-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "switchpoint/router": { + "id": "switchpoint/router", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "kilo-auto/balanced": { + "id": "kilo-auto/balanced", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "kilo-auto/free": { + "id": "kilo-auto/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "kilo-auto/small": { + "id": "kilo-auto/small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "kilo-auto/frontier": { + "id": "kilo-auto/frontier", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "amazon/nova-micro-v1": { + "id": "amazon/nova-micro-v1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 5120, + "input": 128000 + }, + "family": "nova-micro" + }, + "amazon/nova-lite-v1": { + "id": "amazon/nova-lite-v1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 5120, + "input": 300000 + }, + "family": "nova-lite" + }, + "amazon/nova-premier-v1": { + "id": "amazon/nova-premier-v1", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + } + }, + "amazon/nova-2-lite-v1": { + "id": "amazon/nova-2-lite-v1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65535, + "input": 1000000 + }, + "family": "nova" + }, + "amazon/nova-pro-v1": { + "id": "amazon/nova-pro-v1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 32000, + "input": 300000 + }, + "family": "nova-pro" + }, + "anthracite-org/magnum-v4-72b": { + "id": "anthracite-org/magnum-v4-72b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 8192, + "input": 16384 + }, + "family": "llama" + }, + "alibaba/tongyi-deepresearch-30b-a3b": { + "id": "alibaba/tongyi-deepresearch-30b-a3b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "aion-labs/aion-1.0-mini": { + "id": "aion-labs/aion-1.0-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192, + "input": 131072 + }, + "family": "deepseek" + }, + "aion-labs/aion-2.0": { + "id": "aion-labs/aion-2.0", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "aion-labs/aion-rp-llama-3.1-8b": { + "id": "aion-labs/aion-rp-llama-3.1-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384, + "input": 32768 + }, + "family": "llama" + }, + "aion-labs/aion-1.0": { + "id": "aion-labs/aion-1.0", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192, + "input": 65536 + }, + "family": "llama" + }, + "relace/relace-search": { + "id": "relace/relace-search", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "relace/relace-apply-3": { + "id": "relace/relace-apply-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "thedrummer/rocinante-12b": { + "id": "thedrummer/rocinante-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "thedrummer/cydonia-24b-v4.1": { + "id": "thedrummer/cydonia-24b-v4.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "thedrummer/unslopnemo-12b": { + "id": "thedrummer/unslopnemo-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "thedrummer/skyfall-36b-v2": { + "id": "thedrummer/skyfall-36b-v2", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mancer/weaver": { + "id": "mancer/weaver", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 2000 + } + }, + "deepseek/deepseek-r1-distill-qwen-32b": { + "id": "deepseek/deepseek-r1-distill-qwen-32b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "alpindale/goliath-120b": { + "id": "alpindale/goliath-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "output": 1024 + } + }, + "openrouter/hunter-alpha": { + "id": "openrouter/hunter-alpha", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 32000 + } + }, + "openrouter/auto": { + "id": "openrouter/auto", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 32768 + } + }, + "openrouter/healer-alpha": { + "id": "openrouter/healer-alpha", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32000 + } + }, + "openrouter/bodybuilder": { + "id": "openrouter/bodybuilder", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "google/gemini-2.5-pro-preview": { + "id": "google/gemini-2.5-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.0-flash-lite-001": { + "id": "google/gemini-2.0-flash-lite-001", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "z-ai/glm-4-32b": { + "id": "z-ai/glm-4-32b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "deepcogito/cogito-v2.1-671b": { + "id": "deepcogito/cogito-v2.1-671b", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "family": "cogito" + }, + "bytedance/ui-tars-1.5-7b": { + "id": "bytedance/ui-tars-1.5-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 2048 + } + }, + "undi95/remm-slerp-l2-13b": { + "id": "undi95/remm-slerp-l2-13b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "output": 4096, + "input": 6144 + }, + "family": "llama" + }, + "qwen/qwen-vl-plus": { + "id": "qwen/qwen-vl-plus", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen/qwen-vl-max": { + "id": "qwen/qwen-vl-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen/qwen-2.5-vl-7b-instruct": { + "id": "qwen/qwen-2.5-vl-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554 + } + }, + "qwen/qwen3-max-thinking": { + "id": "qwen/qwen3-max-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "qwen/qwen-max": { + "id": "qwen/qwen-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen-turbo": { + "id": "qwen/qwen-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen/qwen3-235b-a22b-2507": { + "id": "qwen/qwen3-235b-a22b-2507", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 52429 + } + }, + "qwen/qwen-2.5-7b-instruct": { + "id": "qwen/qwen-2.5-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 6554 + } + }, + "qwen/qwen-plus": { + "id": "qwen/qwen-plus", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen-plus-2025-07-28": { + "id": "qwen/qwen-plus-2025-07-28", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen3-30b-a3b": { + "id": "Qwen/Qwen3-30B-A3B", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + }, + "family": "qwen" + }, + "qwen/qwen-plus-2025-07-28:thinking": { + "id": "qwen/qwen-plus-2025-07-28:thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen/qwen3.5-flash-02-23": { + "id": "qwen/qwen3.5-flash-02-23", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "eleutherai/llemma_7b": { + "id": "eleutherai/llemma_7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "x-ai/grok-code-fast-1:optimized:free": { + "id": "x-ai/grok-code-fast-1:optimized:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 10000 + } + }, + "meta-llama/llama-4-scout": { + "id": "meta-llama/llama-4-scout", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 328000, + "output": 65536, + "input": 328000 + }, + "family": "llama" + }, + "meta-llama/llama-3.2-3b-instruct": { + "id": "meta-llama/llama-3.2-3b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192, + "input": 131072 + }, + "family": "llama" + }, + "meta-llama/llama-3.2-1b-instruct": { + "id": "meta-llama/llama-3.2-1b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 60000, + "output": 12000 + } + }, + "meta-llama/llama-3.1-405b-instruct": { + "id": "meta-llama/llama-3.1-405b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 26200 + } + }, + "meta-llama/llama-4-maverick": { + "id": "meta-llama/llama-4-maverick", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 1048576 + }, + "family": "llama" + }, + "meta-llama/llama-3.1-405b": { + "id": "meta-llama/llama-3.1-405b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "tngtech/deepseek-r1t2-chimera": { + "id": "tngtech/deepseek-r1t2-chimera", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "mistralai/ministral-3b-2512": { + "id": "mistralai/ministral-3b-2512", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768, + "input": 131072 + }, + "family": "ministral" + }, + "mistralai/mistral-saba": { + "id": "mistralai/mistral-saba", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32768, + "input": 32000 + }, + "family": "mistral" + }, + "mistralai/mistral-small-24b-instruct-2501": { + "id": "mistralai/mistral-small-24b-instruct-2501", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "mistralai/pixtral-large-2411": { + "id": "mistralai/pixtral-large-2411", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "mistralai/mistral-small-creative": { + "id": "mistralai/mistral-small-creative", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768, + "input": 32768 + }, + "family": "mistral-small" + }, + "mistralai/mistral-large-2512": { + "id": "mistralai/mistral-large-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 52429 + } + }, + "mistralai/ministral-8b-2512": { + "id": "mistralai/ministral-8b-2512", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768, + "input": 262144 + }, + "family": "ministral" + }, + "mistralai/ministral-14b-2512": { + "id": "mistralai/ministral-14b-2512", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768, + "input": 262144 + }, + "family": "ministral" + }, + "mistralai/devstral-medium": { + "id": "mistralai/devstral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/mistral-large-2407": { + "id": "mistralai/mistral-large-2407", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "mistralai/devstral-small": { + "id": "mistralai/devstral-small", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/mixtral-8x22b-instruct": { + "id": "mistralai/mixtral-8x22b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 13108 + } + }, + "mistralai/mistral-large-2411": { + "id": "mistralai/mistral-large-2411", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "mistralai/mistral-7b-instruct-v0.1": { + "id": "mistralai/mistral-7b-instruct-v0.1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2824, + "output": 565 + } + }, + "mistralai/mistral-large": { + "id": "mistralai/mistral-large", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 256000, + "input": 128000 + }, + "family": "mistral-large" + }, + "mistralai/mixtral-8x7b-instruct": { + "id": "mistralai/mixtral-8x7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "openai/gpt-4o-2024-11-20": { + "id": "openai/gpt-4o-2024-11-20", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "family": "gpt" + }, + "openai/gpt-4o:extended": { + "id": "openai/gpt-4o:extended", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "openai/gpt-4o-2024-05-13": { + "id": "openai/gpt-4o-2024-05-13", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/gpt-4o-audio-preview": { + "id": "openai/gpt-4o-audio-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4o-mini-2024-07-18": { + "id": "openai/gpt-4o-mini-2024-07-18", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-audio": { + "id": "openai/gpt-audio", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-3.5-turbo-16k": { + "id": "openai/gpt-3.5-turbo-16k", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 4096 + } + }, + "openai/gpt-5-image-mini": { + "id": "openai/gpt-5-image-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "image", + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai/gpt-4-turbo-preview": { + "id": "openai/gpt-4-turbo-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096, + "input": 128000 + }, + "family": "gpt" + }, + "openai/gpt-3.5-turbo-0613": { + "id": "openai/gpt-3.5-turbo-0613", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4095, + "output": 4096 + } + }, + "openai/gpt-4-0314": { + "id": "openai/gpt-4-0314", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8191, + "output": 4096 + } + }, + "openai/gpt-audio-mini": { + "id": "openai/gpt-audio-mini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "openai/gpt-4-1106-preview": { + "id": "openai/gpt-4-1106-preview", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "openai/gpt-4o-2024-08-06": { + "id": "openai/gpt-4o-2024-08-06", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "family": "gpt" + }, + "openai/o4-mini-high": { + "id": "openai/o4-mini-high", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 200000 + }, + "family": "o-mini" + }, + "openai/gpt-4o-search-preview": { + "id": "openai/gpt-4o-search-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 128000 + }, + "family": "gpt" + }, + "cohere/command-r-08-2024": { + "id": "cohere/command-r-08-2024", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "cohere/command-r-plus-08-2024": { + "id": "cohere/command-r-plus-08-2024", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096, + "input": 128000 + }, + "family": "command-r" + }, + "cohere/command-r7b-12-2024": { + "id": "cohere/command-r7b-12-2024", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4000 + } + }, + "minimax/minimax-m2-her": { + "id": "minimax/minimax-m2-her", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65532, + "output": 2048, + "input": 65532 + }, + "family": "minimax" + }, + "minimax/minimax-m2.5:free": { + "id": "minimax/minimax-m2.5:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "sao10k/l3.1-70b-hanami-x1": { + "id": "Sao10K/L3.1-70B-Hanami-x1", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384, + "input": 16384 + }, + "family": "llama" + }, + "sao10k/l3-lunaris-8b": { + "id": "sao10k/l3-lunaris-8b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3.1-euryale-70b": { + "id": "sao10k/l3.1-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "sao10k/l3-euryale-70b": { + "id": "sao10k/l3-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "sao10k/l3.3-euryale-70b": { + "id": "sao10k/l3.3-euryale-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "writer/palmyra-x5": { + "id": "writer/palmyra-x5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1040000, + "output": 8192 + } + }, + "perplexity/sonar-deep-research": { + "id": "perplexity/sonar-deep-research", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 25600 + } + }, + "perplexity/sonar-pro-search": { + "id": "perplexity/sonar-pro-search", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8000 + } + }, + "bytedance-seed/seed-2.0-mini": { + "id": "bytedance-seed/seed-2.0-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "bytedance-seed/seed-1.6": { + "id": "bytedance-seed/seed-1.6", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "bytedance-seed/seed-1.6-flash": { + "id": "bytedance-seed/seed-1.6-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "bytedance-seed/seed-2.0-lite": { + "id": "bytedance-seed/seed-2.0-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "anthropic/claude-3.7-sonnet:thinking": { + "id": "anthropic/claude-3.7-sonnet:thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000 + } + }, + "ai21/jamba-large-1.7": { + "id": "ai21/jamba-large-1.7", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "kilo/auto": { + "id": "kilo/auto", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "kilo/auto-free": { + "id": "kilo/auto-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "kilo/auto-small": { + "id": "kilo/auto-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "inflection/inflection-3-productivity": { + "id": "inflection/inflection-3-productivity", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 4096, + "input": 8000 + }, + "family": "gpt" + }, + "inflection/inflection-3-pi": { + "id": "inflection/inflection-3-pi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 4096, + "input": 8000 + }, + "family": "gpt" + }, + "nousresearch/hermes-3-llama-3.1-70b": { + "id": "nousresearch/hermes-3-llama-3.1-70b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "nousresearch/hermes-3-llama-3.1-405b": { + "id": "nousresearch/hermes-3-llama-3.1-405b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "exa-research-pro": { + "id": "exa-research-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "gemini-2.0-pro-exp-02-05": { + "id": "gemini-2.0-pro-exp-02-05", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2097152, + "input": 2097152, + "output": 8192 + } + }, + "qwen-image": { + "id": "qwen-image", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "llama-3.3-70b-shakudo": { + "id": "Llama-3.3-70B-Shakudo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "ernie-4.5-8k-preview": { + "id": "ernie-4.5-8k-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 16384 + } + }, + "claude-3-7-sonnet-thinking:128000": { + "id": "claude-3-7-sonnet-thinking:128000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "phi-4-multimodal-instruct": { + "id": "phi-4-multimodal-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "z-image-turbo": { + "id": "z-image-turbo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "llama-3.3+(3v3.3)-70b-tenyxchat-daybreakstorywriter": { + "id": "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "mistral-small-31-24b-instruct": { + "id": "mistral-small-31-24b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + } + }, + "llama-3.3-70b-the-omega-directive-unslop-v2.0": { + "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "baichuan-m2": { + "id": "Baichuan-M2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "doubao-1.5-vision-pro-32k": { + "id": "doubao-1.5-vision-pro-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "glm-4.5-air-derestricted-iceblink-v2-reextract": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-v2-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + } + }, + "llama-3.3-70b-arliai-rpmax-v1.4": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v1.4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "jamba-large-1.6": { + "id": "jamba-large-1.6", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "llama-3.3-70b-aurora-borealis": { + "id": "Llama-3.3-70B-Aurora-Borealis", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "ernie-x1-32k": { + "id": "ernie-x1-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "llama-3.3-70b-magnum-v4-se": { + "id": "Llama-3.3-70B-Magnum-v4-SE", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "kat-coder-pro-v1": { + "id": "KAT-Coder-Pro-V1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + } + }, + "hunyuan-turbos-20250226": { + "id": "hunyuan-turbos-20250226", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 24000, + "input": 24000, + "output": 8192 + } + }, + "jamba-large-1.7": { + "id": "jamba-large-1.7", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "mercury-coder-small": { + "id": "mercury-coder-small", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-1-5-thinking-pro-vision-250415": { + "id": "doubao-1-5-thinking-pro-vision-250415", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "yi-medium-200k": { + "id": "yi-medium-200k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 4096 + } + }, + "deepseek-chat-cheaper": { + "id": "deepseek-chat-cheaper", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "step-r1-v-mini": { + "id": "step-r1-v-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "yi-lightning": { + "id": "yi-lightning", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 12000, + "input": 12000, + "output": 4096 + } + }, + "deepseek-reasoner-cheaper": { + "id": "deepseek-reasoner-cheaper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "ernie-4.5-turbo-vl-32k": { + "id": "ernie-4.5-turbo-vl-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "llama-3.3-70b-ignition-v0.1": { + "id": "Llama-3.3-70B-Ignition-v0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-z1-air": { + "id": "glm-z1-air", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "llama-3.3-70b-rawmaw": { + "id": "Llama-3.3-70B-RAWMAW", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "magistral-small-2506": { + "id": "Magistral-Small-2506", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "ernie-x1-turbo-32k": { + "id": "ernie-x1-turbo-32k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "deepseek-r1-sambanova": { + "id": "deepseek-r1-sambanova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "claude-3-7-sonnet-thinking:1024": { + "id": "claude-3-7-sonnet-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "llama-3.3-70b-magnum-v4-se-cirrus-x1-slerp": { + "id": "Llama-3.3-70B-Magnum-v4-SE-Cirrus-x1-SLERP", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-arliai-rpmax-v3": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwen-long": { + "id": "qwen-long", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 10000000, + "input": 10000000, + "output": 8192 + }, + "family": "qwen", + "temperature": true + }, + "llama-3.3-70b-progenitor-v3.3": { + "id": "Llama-3.3-70B-Progenitor-V3.3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.5-air-derestricted-iceblink-v2": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 158600, + "input": 158600, + "output": 65536 + } + }, + "study_gpt-chatgpt-4o-latest": { + "id": "study_gpt-chatgpt-4o-latest", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 16384 + } + }, + "qwq-32b": { + "id": "qwq-32b", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 8192 + }, + "family": "qwen", + "temperature": true + }, + "llama-3.3-70b-ms-nevoria": { + "id": "Llama-3.3-70B-MS-Nevoria", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-seed-1-6-250615": { + "id": "doubao-seed-1-6-250615", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "glm-4": { + "id": "glm-4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "azure-gpt-4-turbo": { + "id": "azure-gpt-4-turbo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "llama-3.3-70b-legion-v2.1": { + "id": "Llama-3.3-70B-Legion-V2.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-3-7-sonnet-thinking:32768": { + "id": "claude-3-7-sonnet-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "asi1-mini": { + "id": "asi1-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "gemini-exp-1206": { + "id": "gemini-exp-1206", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2097152, + "input": 2097152, + "output": 8192 + } + }, + "brave": { + "id": "brave", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "doubao-1-5-thinking-pro-250415": { + "id": "doubao-1-5-thinking-pro-250415", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "claude-sonnet-4-thinking:64000": { + "id": "claude-sonnet-4-thinking:64000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "glm-4.5-air-derestricted-steam-reextract": { + "id": "GLM-4.5-Air-Derestricted-Steam-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 65536 + } + }, + "kimi-k2-instruct-fast": { + "id": "kimi-k2-instruct-fast", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "llama-3.3-70b-geneticlemonade-opus": { + "id": "Llama-3.3-70B-GeneticLemonade-Opus", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemma-3-27b-big-tiger-v3": { + "id": "Gemma-3-27B-Big-Tiger-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-seed-2-0-mini-260215": { + "id": "doubao-seed-2-0-mini-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32000 + } + }, + "glm-4-air": { + "id": "glm-4-air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "glm-4.5-air-derestricted-iceblink-reextract": { + "id": "GLM-4.5-Air-Derestricted-Iceblink-ReExtract", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + } + }, + "gemini-2.0-pro-reasoner": { + "id": "gemini-2.0-pro-reasoner", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "gemini-2.0-flash-001": { + "id": "gemini-2.0-flash-001", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + } + }, + "glm-4-plus": { + "id": "glm-4-plus", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "gemini-2.0-flash-exp-image-generation": { + "id": "gemini-2.0-flash-exp-image-generation", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "glm-4.5-air-derestricted": { + "id": "GLM-4.5-Air-Derestricted", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202600, + "input": 202600, + "output": 98304 + } + }, + "gemini-2.0-flash-thinking-exp-1219": { + "id": "gemini-2.0-flash-thinking-exp-1219", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "glm-4.1v-thinking-flashx": { + "id": "glm-4.1v-thinking-flashx", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "llama-3.3-70b-strawberrylemonade-v1.0": { + "id": "Llama-3.3-70B-StrawberryLemonade-v1.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-fallen-v1": { + "id": "Llama-3.3-70B-Fallen-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemma-3-27b-nidum-uncensored": { + "id": "Gemma-3-27B-Nidum-Uncensored", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + } + }, + "llama-3.3-70b-electranova-v1.0": { + "id": "Llama-3.3-70B-Electranova-v1.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "grok-3-fast-beta": { + "id": "grok-3-fast-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "llama-3.3-70b-sapphira-0.1": { + "id": "Llama-3.3-70B-Sapphira-0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemini-2.5-pro-preview-03-25": { + "id": "gemini-2.5-pro-preview-03-25", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "step-2-16k-exp": { + "id": "step-2-16k-exp", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 16000, + "output": 8192 + } + }, + "chroma": { + "id": "chroma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "fastgpt": { + "id": "fastgpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "claude-sonnet-4-thinking:8192": { + "id": "claude-sonnet-4-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "llama-3.3-70b-electra-r1": { + "id": "Llama-3.3-70B-Electra-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-fallen-r1-v1": { + "id": "Llama-3.3-70B-Fallen-R1-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemma-3-27b-it-abliterated": { + "id": "Gemma-3-27B-it-Abliterated", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + } + }, + "doubao-1.5-pro-256k": { + "id": "doubao-1.5-pro-256k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "claude-opus-4-thinking": { + "id": "claude-opus-4-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "doubao-1-5-thinking-vision-pro-250428": { + "id": "doubao-1-5-thinking-vision-pro-250428", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "doubao-seed-2-0-lite-260215": { + "id": "doubao-seed-2-0-lite-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32000 + } + }, + "qwen25-vl-72b-instruct": { + "id": "qwen25-vl-72b-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 32768 + } + }, + "azure-gpt-4o": { + "id": "azure-gpt-4o", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "ernie-4.5-turbo-128k": { + "id": "ernie-4.5-turbo-128k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "azure-o1": { + "id": "azure-o1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "gemini-3-pro-preview-thinking": { + "id": "gemini-3-pro-preview-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "grok-3-mini-beta": { + "id": "grok-3-mini-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "claude-opus-4-1-thinking": { + "id": "claude-opus-4-1-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "gemini-2.5-flash-nothinking": { + "id": "gemini-2.5-flash-nothinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "claude-3-7-sonnet-thinking:8192": { + "id": "claude-3-7-sonnet-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + } + }, + "auto-model-basic": { + "id": "auto-model-basic", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "llama-3.3-70b-the-omega-directive-unslop-v2.1": { + "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4-plus-0111": { + "id": "glm-4-plus-0111", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "llama-3.3-70b-bigger-body": { + "id": "Llama-3.3-70B-Bigger-Body", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "kat-coder-air-v1": { + "id": "KAT-Coder-Air-V1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "doubao-seed-1-6-flash-250615": { + "id": "doubao-seed-1-6-flash-250615", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "glm-4-air-0111": { + "id": "glm-4-air-0111", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "phi-4-mini-instruct": { + "id": "phi-4-mini-instruct", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "jamba-mini-1.6": { + "id": "jamba-mini-1.6", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "kimi-thinking-preview": { + "id": "kimi-thinking-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "claude-sonnet-4-thinking:1024": { + "id": "claude-sonnet-4-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "llama-3.3-70b-incandescent-malevolence": { + "id": "Llama-3.3-70B-Incandescent-Malevolence", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-forgotten-safeword-3.6": { + "id": "Llama-3.3-70B-Forgotten-Safeword-3.6", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "step-2-mini": { + "id": "step-2-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + } + }, + "mistral-nemo-12b-instruct-2407": { + "id": "Mistral-Nemo-12B-Instruct-2407", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "baichuan4-turbo": { + "id": "Baichuan4-Turbo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "ernie-5.0-thinking-latest": { + "id": "ernie-5.0-thinking-latest", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "gemma-3-27b-glitter": { + "id": "Gemma-3-27B-Glitter", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-thinking:32000": { + "id": "claude-opus-4-thinking:32000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "auto-model-premium": { + "id": "auto-model-premium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "gemini-2.0-flash-thinking-exp-01-21": { + "id": "gemini-2.0-flash-thinking-exp-01-21", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 8192 + } + }, + "claude-sonnet-4-thinking:32768": { + "id": "claude-sonnet-4-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "claude-opus-4-1-thinking:32768": { + "id": "claude-opus-4-1-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "jamba-large": { + "id": "jamba-large", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "llama-3.3-70b-miraifanfare": { + "id": "Llama-3.3-70B-MiraiFanfare", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "venice-uncensored:web": { + "id": "venice-uncensored:web", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "input": 80000, + "output": 16384 + } + }, + "gemini-2.5-flash-lite-preview-09-2025-thinking": { + "id": "gemini-2.5-flash-lite-preview-09-2025-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "ernie-x1-32k-preview": { + "id": "ernie-x1-32k-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "glm-z1-airx": { + "id": "glm-z1-airx", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 16384 + } + }, + "ernie-x1.1-preview": { + "id": "ernie-x1.1-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "exa-research": { + "id": "exa-research", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "llama-3.3-70b-mokume-gane-r1": { + "id": "Llama-3.3-70B-Mokume-Gane-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.1v-thinking-flash": { + "id": "glm-4.1v-thinking-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 8192 + } + }, + "llama-3.3-70b-geneticlemonade-unleashed-v3": { + "id": "Llama-3.3-70B-GeneticLemonade-Unleashed-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-predatorial-extasy": { + "id": "Llama-3.3-70B-Predatorial-Extasy", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4-airx": { + "id": "glm-4-airx", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + } + }, + "doubao-seed-1-6-thinking-250615": { + "id": "doubao-seed-1-6-thinking-250615", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "claude-3-7-sonnet-thinking": { + "id": "claude-3-7-sonnet-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 16000 + } + }, + "glm-4.5-air-derestricted-steam": { + "id": "GLM-4.5-Air-Derestricted-Steam", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 220600, + "input": 220600, + "output": 65536 + } + }, + "ernie-5.0-thinking-preview": { + "id": "ernie-5.0-thinking-preview", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "claude-opus-4-thinking:1024": { + "id": "claude-opus-4-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-strawberrylemonade-v1.2": { + "id": "Llama-3.3-70B-Strawberrylemonade-v1.2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-vulpecula-r1": { + "id": "Llama-3.3-70B-Vulpecula-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4.6-derestricted-v5": { + "id": "GLM-4.6-Derestricted-v5", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "llama-3.3-70b-cirrus-x1": { + "id": "Llama-3.3-70B-Cirrus-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "llama-3.3-70b-arliai-rpmax-v2": { + "id": "Llama-3.3-70B-ArliAI-RPMax-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-seed-code-preview-latest": { + "id": "doubao-seed-code-preview-latest", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "llama-3.3+(3.1v3.3)-70b-new-dawn-v1.1": { + "id": "Llama-3.3+(3.1v3.3)-70B-New-Dawn-v1.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "qwen3-vl-235b-a22b-thinking": { + "id": "qwen3-vl-235b-a22b-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "claude-sonnet-4-thinking": { + "id": "claude-sonnet-4-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 64000 + } + }, + "qwen2.5-32b-eva-v0.2": { + "id": "Qwen2.5-32B-EVA-v0.2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 24576, + "input": 24576, + "output": 8192 + } + }, + "llama-3.3-70b-cu-mai-r1": { + "id": "Llama-3.3-70B-Cu-Mai-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "hidream": { + "id": "hidream", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "auto-model": { + "id": "auto-model", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "jamba-mini-1.7": { + "id": "jamba-mini-1.7", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "doubao-seed-2-0-pro-260215": { + "id": "doubao-seed-2-0-pro-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + } + }, + "llama-3.3-70b-nova": { + "id": "Llama-3.3-70B-Nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemini-2.5-flash-preview-09-2025-thinking": { + "id": "gemini-2.5-flash-preview-09-2025-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "llama-3.3-70b-sapphira-0.2": { + "id": "Llama-3.3-70B-Sapphira-0.2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "auto-model-standard": { + "id": "auto-model-standard", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "grok-3-mini-fast-beta": { + "id": "grok-3-mini-fast-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "meta-llama-3-1-8b-instruct-fp8": { + "id": "Meta-Llama-3-1-8B-Instruct-FP8", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "step-3": { + "id": "step-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "universal-summarizer": { + "id": "universal-summarizer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "deepclaude": { + "id": "deepclaude", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "brave-pro": { + "id": "brave-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "claude-3-7-sonnet-reasoner": { + "id": "claude-3-7-sonnet-reasoner", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "claude-opus-4-thinking:8192": { + "id": "claude-opus-4-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "claude-opus-4-thinking:32768": { + "id": "claude-opus-4-thinking:32768", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "glm-zero-preview": { + "id": "glm-zero-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 4096 + } + }, + "azure-gpt-4o-mini": { + "id": "azure-gpt-4o-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "deepseek-math-v2": { + "id": "deepseek-math-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "glm-4-long": { + "id": "glm-4-long", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 4096 + } + }, + "glm-4.5-air-derestricted-iceblink": { + "id": "GLM-4.5-Air-Derestricted-Iceblink", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 98304 + } + }, + "claude-opus-4-1-thinking:1024": { + "id": "claude-opus-4-1-thinking:1024", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "qwen3-vl-235b-a22b-instruct-original": { + "id": "qwen3-vl-235b-a22b-instruct-original", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "llama-3.3+(3.1v3.3)-70b-hanami-x1": { + "id": "Llama-3.3+(3.1v3.3)-70B-Hanami-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-1-thinking:8192": { + "id": "claude-opus-4-1-thinking:8192", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "llama-3.3-70b-damascus-r1": { + "id": "Llama-3.3-70B-Damascus-R1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemma-3-27b-arliai-rpmax-v3": { + "id": "Gemma-3-27B-ArliAI-RPMax-v3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "gemini-2.5-flash-preview-05-20:thinking": { + "id": "gemini-2.5-flash-preview-05-20:thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048000, + "input": 1048000, + "output": 65536 + } + }, + "claude-opus-4-1-thinking:32000": { + "id": "claude-opus-4-1-thinking:32000", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "sarvan-medium": { + "id": "sarvan-medium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "llama-3.3-70b-anthrobomination": { + "id": "Llama-3.3-70B-Anthrobomination", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "baichuan4-air": { + "id": "Baichuan4-Air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "jamba-mini": { + "id": "jamba-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 4096 + } + }, + "kat-coder-exp-72b-1010": { + "id": "KAT-Coder-Exp-72B-1010", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "gemini-2.5-flash-preview-04-17:thinking": { + "id": "gemini-2.5-flash-preview-04-17:thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "brave-research": { + "id": "brave-research", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "llama-3.3-70b-argunaut-1-sft": { + "id": "Llama-3.3-70B-Argunaut-1-SFT", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "claude-opus-4-5-20251101:thinking": { + "id": "claude-opus-4-5-20251101:thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + } + }, + "grok-3-beta": { + "id": "grok-3-beta", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + } + }, + "azure-o3-mini": { + "id": "azure-o3-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 65536 + } + }, + "qwq-32b-arliai-rpr-v1": { + "id": "QwQ-32B-ArliAI-RpR-v1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "llama-3.3-70b-forgotten-abomination-v5.0": { + "id": "Llama-3.3-70B-Forgotten-Abomination-v5.0", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "doubao-seed-2-0-code-preview-260215": { + "id": "doubao-seed-2-0-code-preview-260215", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 128000 + } + }, + "llama-3.3-70b-mhnnn-x1": { + "id": "Llama-3.3-70B-Mhnnn-x1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "hunyuan-t1-latest": { + "id": "hunyuan-t1-latest", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "gemma-3-27b-cardprojector-v4": { + "id": "Gemma-3-27B-CardProjector-v4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "glm-4-flash": { + "id": "glm-4-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "learnlm-1.5-pro-experimental": { + "id": "learnlm-1.5-pro-experimental", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32767, + "input": 32767, + "output": 8192 + } + }, + "llama-3.3-70b-dark-ages-v0.1": { + "id": "Llama-3.3-70B-Dark-Ages-v0.1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "yi-large": { + "id": "yi-large", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 4096 + } + }, + "exa-answer": { + "id": "exa-answer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 4096, + "output": 4096 + } + }, + "gemini-2.5-pro-exp-03-25": { + "id": "gemini-2.5-pro-exp-03-25", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "llm360/k2-think": { + "id": "LLM360/K2-Think", + "family": "kimi-thinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "abacusai/dracarys-72b-instruct": { + "id": "abacusai/Dracarys-72B-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "envoid/llama-3.05-nemotron-tenyxchat-storybreaker-70b": { + "id": "Envoid/Llama-3.05-Nemotron-Tenyxchat-Storybreaker-70B", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "envoid/llama-3.05-nt-storybreaker-ministral-70b": { + "id": "Envoid/Llama-3.05-NT-Storybreaker-Ministral-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "zai-org/glm-5:thinking": { + "id": "zai-org/glm-5:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 128000 + } + }, + "nvidia/llama-3.1-nemotron-70b-instruct-hf": { + "id": "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "nvidia/llama-3_3-nemotron-super-49b-v1_5": { + "id": "nvidia/Llama-3_3-Nemotron-Super-49B-v1_5", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "doctor-shotgun/ms3.2-24b-magnum-diamond": { + "id": "Doctor-Shotgun/MS3.2-24B-Magnum-Diamond", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "arcee-ai/trinity-large": { + "id": "arcee-ai/trinity-large", + "family": "trinity", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "meganova-ai/manta-flash-1.0": { + "id": "meganova-ai/manta-flash-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "meganova-ai/manta-pro-1.0": { + "id": "meganova-ai/manta-pro-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "meganova-ai/manta-mini-1.0": { + "id": "meganova-ai/manta-mini-1.0", + "family": "nova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "xiaomi/mimo-v2-flash-original": { + "id": "xiaomi/mimo-v2-flash-original", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + } + }, + "xiaomi/mimo-v2-flash-thinking": { + "id": "xiaomi/mimo-v2-flash-thinking", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + } + }, + "xiaomi/mimo-v2-flash-thinking-original": { + "id": "xiaomi/mimo-v2-flash-thinking-original", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 32768 + } + }, + "microsoft/mai-ds-r1-fp8": { + "id": "microsoft/MAI-DS-R1-FP8", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "failspy/meta-llama-3-70b-instruct-abliterated-v3.5": { + "id": "failspy/Meta-Llama-3-70B-Instruct-abliterated-v3.5", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "featherless-ai/qwerky-72b": { + "id": "featherless-ai/Qwerky-72B", + "family": "qwerky", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "tee/glm-5": { + "id": "TEE/glm-5", + "family": "glm", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + } + }, + "tee/deepseek-v3.1": { + "id": "TEE/deepseek-v3.1", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 164000, + "output": 8192 + } + }, + "tee/glm-4.7-flash": { + "id": "TEE/glm-4.7-flash", + "family": "glm-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + } + }, + "tee/qwen3-coder": { + "id": "TEE/qwen3-coder", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "tee/glm-4.6": { + "id": "TEE/glm-4.6", + "family": "glm", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 203000, + "input": 203000, + "output": 65535 + } + }, + "tee/deepseek-r1-0528": { + "id": "TEE/deepseek-r1-0528", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "tee/minimax-m2.1": { + "id": "TEE/minimax-m2.1", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + } + }, + "tee/qwen3.5-397b-a17b": { + "id": "TEE/qwen3.5-397b-a17b", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 258048, + "input": 258048, + "output": 65536 + } + }, + "tee/gpt-oss-120b": { + "id": "TEE/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "tee/kimi-k2.5": { + "id": "TEE/kimi-k2.5", + "family": "kimi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + } + }, + "tee/qwen3-30b-a3b-instruct-2507": { + "id": "TEE/qwen3-30b-a3b-instruct-2507", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "input": 262000, + "output": 32768 + } + }, + "tee/kimi-k2.5-thinking": { + "id": "TEE/kimi-k2.5-thinking", + "family": "kimi-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + } + }, + "tee/qwen2.5-vl-72b-instruct": { + "id": "TEE/qwen2.5-vl-72b-instruct", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "tee/deepseek-v3.2": { + "id": "TEE/deepseek-v3.2", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 164000, + "output": 65536 + } + }, + "tee/glm-4.7": { + "id": "TEE/glm-4.7", + "family": "glm", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 131000, + "output": 65535 + } + }, + "tee/kimi-k2-thinking": { + "id": "TEE/kimi-k2-thinking", + "family": "kimi-thinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65535 + } + }, + "tee/llama3-3-70b": { + "id": "TEE/llama3-3-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "tee/gemma-3-27b-it": { + "id": "TEE/gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "tee/gpt-oss-20b": { + "id": "TEE/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8192 + } + }, + "anthracite-org/magnum-v2-72b": { + "id": "anthracite-org/magnum-v2-72b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "nousresearch 2/hermes-4-405b": { + "id": "NousResearch 2/hermes-4-405b", + "family": "nousresearch", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "nousresearch 2/hermes-3-llama-3.1-70b": { + "id": "NousResearch 2/hermes-3-llama-3.1-70b", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "nousresearch 2/deephermes-3-mistral-24b-preview": { + "id": "NousResearch 2/DeepHermes-3-Mistral-24B-Preview", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "nousresearch 2/hermes-4-70b": { + "id": "NousResearch 2/hermes-4-70b", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "nousresearch 2/hermes-4-405b:thinking": { + "id": "NousResearch 2/hermes-4-405b:thinking", + "family": "nousresearch", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "nousresearch 2/hermes-4-70b:thinking": { + "id": "NousResearch 2/Hermes-4-70B:thinking", + "family": "nousresearch", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "pamanseau/openreasoning-nemotron-32b": { + "id": "pamanseau/OpenReasoning-Nemotron-32B", + "family": "nemotron", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-exp-thinking": { + "id": "deepseek-ai/deepseek-v3.2-exp-thinking", + "family": "deepseek-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1:thinking": { + "id": "deepseek-ai/DeepSeek-V3.1:thinking", + "family": "deepseek-thinking", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1-terminus:thinking": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus:thinking", + "family": "deepseek-thinking", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "raifle/sorcererlm-8x22b": { + "id": "raifle/sorcererlm-8x22b", + "family": "mixtral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 16000, + "output": 8192 + } + }, + "mlabonne/neuraldaredevil-8b-abliterated": { + "id": "mlabonne/NeuralDaredevil-8B-abliterated", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "unsloth/gemma-3-1b-it": { + "id": "unsloth/gemma-3-1b-it", + "family": "unsloth", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "unsloth/gemma-3-12b-it": { + "id": "unsloth/gemma-3-12b-it", + "family": "unsloth", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true + }, + "unsloth/gemma-3-4b-it": { + "id": "unsloth/gemma-3-4b-it", + "family": "unsloth", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 96000, + "input": 128000, + "output": 96000 + }, + "temperature": true + }, + "unsloth/gemma-3-27b-it": { + "id": "unsloth/gemma-3-27b-it", + "family": "unsloth", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + }, + "temperature": true + }, + "meituan-longcat/longcat-flash-chat-fp8": { + "id": "meituan-longcat/LongCat-Flash-Chat-FP8", + "family": "longcat", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "cognitivecomputations/dolphin-2.9.2-qwen2-72b": { + "id": "cognitivecomputations/dolphin-2.9.2-qwen2-72b", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 4096 + } + }, + "infermatic/mn-12b-inferor-v0.0": { + "id": "Infermatic/MN-12B-Inferor-v0.0", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "cruciblelab/l3.3-70b-loki-v2.0": { + "id": "CrucibleLab/L3.3-70B-Loki-V2.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "soob3123/veiled-calla-12b": { + "id": "soob3123/Veiled-Calla-12B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "soob3123/amoral-gemma3-27b-v2": { + "id": "soob3123/amoral-gemma3-27B-v2", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "soob3123/grayline-qwen3-8b": { + "id": "soob3123/GrayLine-Qwen3-8B", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "neversleep/llama-3-lumimaid-70b-v0.1": { + "id": "NeverSleep/Llama-3-Lumimaid-70B-v0.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "neversleep/lumimaid-v0.2-70b": { + "id": "NeverSleep/Lumimaid-v0.2-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "deepseek/deepseek-v3.2:thinking": { + "id": "deepseek/deepseek-v3.2:thinking", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163000, + "input": 163000, + "output": 65536 + } + }, + "marinaraspaghetti/nemomix-unleashed-12b": { + "id": "MarinaraSpaghetti/NemoMix-Unleashed-12B", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "moonshotai/kimi-k2.5:thinking": { + "id": "moonshotai/kimi-k2.5:thinking", + "family": "kimi-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 65536 + } + }, + "moonshotai/kimi-k2-thinking-turbo-original": { + "id": "moonshotai/kimi-k2-thinking-turbo-original", + "family": "kimi-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "moonshotai/kimi-k2-instruct-0711": { + "id": "moonshotai/kimi-k2-instruct-0711", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "moonshotai/kimi-dev-72b": { + "id": "moonshotai/Kimi-Dev-72B", + "family": "kimi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + } + }, + "moonshotai/kimi-k2-thinking-original": { + "id": "moonshotai/kimi-k2-thinking-original", + "family": "kimi-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "google/gemini-flash-1.5": { + "id": "google/gemini-flash-1.5", + "family": "gemini-flash", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 8192 + } + }, + "google/gemini-3-flash-preview-thinking": { + "id": "google/gemini-3-flash-preview-thinking", + "family": "gemini-flash", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "z-ai/glm-4.6:thinking": { + "id": "z-ai/glm-4.6:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 65535 + } + }, + "z-ai/glm-4.5v:thinking": { + "id": "z-ai/glm-4.5v:thinking", + "family": "glmv", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 96000 + } + }, + "stepfun-ai/step-3.5-flash:thinking": { + "id": "stepfun-ai/step-3.5-flash:thinking", + "family": "step", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "deepcogito/cogito-v1-preview-qwen-32b": { + "id": "deepcogito/cogito-v1-preview-qwen-32B", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + } + }, + "inflatebot/mn-12b-mag-mell-r1": { + "id": "inflatebot/MN-12B-Mag-Mell-R1", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "nothingiisreal/l3.1-70b-celeste-v0.1-bf16": { + "id": "nothingiisreal/L3.1-70B-Celeste-V0.1-BF16", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "x-ai/grok-4-fast:thinking": { + "id": "x-ai/grok-4-fast:thinking", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 131072 + } + }, + "x-ai/grok-4-07-09": { + "id": "x-ai/grok-4-07-09", + "family": "grok", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 131072 + } + }, + "tngtech/deepseek-tng-r1t2-chimera": { + "id": "tngtech/DeepSeek-TNG-R1T2-Chimera", + "family": "tngtech", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 128000, + "output": 163840 + }, + "temperature": true + }, + "tngtech/tng-r1t-chimera": { + "id": "tngtech/tng-r1t-chimera", + "family": "tngtech", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "mistralai/mixtral-8x22b-instruct-v0.1": { + "id": "mistralai/mixtral-8x22b-instruct-v0.1", + "family": "mixtral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 32768 + } + }, + "mistralai/mistral-tiny": { + "id": "mistralai/mistral-tiny", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 8192 + } + }, + "mistralai/mistral-7b-instruct": { + "id": "mistralai/mistral-7b-instruct", + "family": "mistral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "mistralai/mixtral-8x7b-instruct-v0.1": { + "id": "mistralai/mixtral-8x7b-instruct-v0.1", + "family": "mixtral", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "tongyi-zhiwen/qwenlong-l1-32b": { + "id": "Tongyi-Zhiwen/QwenLong-L1-32B", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 40960 + } + }, + "readyart/the-omega-abomination-l-70b-v1.0": { + "id": "ReadyArt/The-Omega-Abomination-L-70B-v1.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "readyart/ms3.2-the-omega-directive-24b-unslop-v2.0": { + "id": "ReadyArt/MS3.2-The-Omega-Directive-24B-Unslop-v2.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "openai/gpt-5.1-2025-11-13": { + "id": "openai/gpt-5.1-2025-11-13", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 32768 + } + }, + "openai/gpt-5-chat-latest": { + "id": "openai/gpt-5-chat-latest", + "family": "gpt", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 400000, + "output": 128000 + } + }, + "openai/o3-mini-low": { + "id": "openai/o3-mini-low", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/o3-pro-2025-06-10": { + "id": "openai/o3-pro-2025-06-10", + "family": "o-pro", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/gpt-5.1-chat-latest": { + "id": "openai/gpt-5.1-chat-latest", + "family": "gpt", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 400000, + "output": 16384 + } + }, + "vongolachouko/starcannon-unleashed-12b-v1.0": { + "id": "VongolaChouko/Starcannon-Unleashed-12B-v1.0", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "cohere/command-r": { + "id": "cohere/command-r", + "family": "command-r", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "thudm/glm-z1-rumination-32b-0414": { + "id": "THUDM/GLM-Z1-Rumination-32B-0414", + "family": "glm-z", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 65536 + } + }, + "chutesai/mistral-small-3.2-24b-instruct-2506": { + "id": "chutesai/Mistral-Small-3.2-24B-Instruct-2506", + "family": "chutesai", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true + }, + "baseten/kimi-k2-instruct-fp4": { + "id": "baseten/Kimi-K2-Instruct-FP4", + "family": "kimi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 131072 + } + }, + "galrionsoftworks/mn-loosecannon-12b-v1": { + "id": "GalrionSoftworks/MN-LooseCannon-12B-v1", + "family": "mistral-nemo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "alibaba-nlp/tongyi-deepresearch-30b-a3b": { + "id": "Alibaba-NLP/Tongyi-DeepResearch-30B-A3B", + "family": "yi", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "steelskull/l3.3-electra-r1-70b": { + "id": "Steelskull/L3.3-Electra-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-evalebis-70b": { + "id": "Steelskull/L3.3-MS-Evalebis-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-cu-mai-r1-70b": { + "id": "Steelskull/L3.3-Cu-Mai-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-nevoria-r1-70b": { + "id": "Steelskull/L3.3-Nevoria-R1-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-nevoria-70b": { + "id": "Steelskull/L3.3-MS-Nevoria-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "steelskull/l3.3-ms-evayale-70b": { + "id": "Steelskull/L3.3-MS-Evayale-70B", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "salesforce/llama-xlam-2-70b-fc-r": { + "id": "Salesforce/Llama-xLAM-2-70b-fc-r", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "latitudegames/wayfarer-large-70b-llama-3.3": { + "id": "LatitudeGames/Wayfarer-Large-70B-Llama-3.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "thedrummer 2/cydonia-24b-v4.3": { + "id": "TheDrummer 2/Cydonia-24B-v4.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "thedrummer 2/anubis-70b-v1": { + "id": "TheDrummer 2/Anubis-70B-v1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 16384 + } + }, + "thedrummer 2/cydonia-24b-v4": { + "id": "TheDrummer 2/Cydonia-24B-v4", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "thedrummer 2/magidonia-24b-v4.3": { + "id": "TheDrummer 2/Magidonia-24B-v4.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "thedrummer 2/anubis-70b-v1.1": { + "id": "TheDrummer 2/Anubis-70B-v1.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 16384 + } + }, + "thedrummer 2/rocinante-12b-v1.1": { + "id": "TheDrummer 2/Rocinante-12B-v1.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "thedrummer 2/cydonia-24b-v2": { + "id": "TheDrummer 2/Cydonia-24B-v2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "thedrummer 2/skyfall-36b-v2": { + "id": "TheDrummer 2/skyfall-36b-v2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "input": 64000, + "output": 32768 + } + }, + "thedrummer 2/unslopnemo-12b-v4.1": { + "id": "TheDrummer 2/UnslopNemo-12B-v4.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "thedrummer 2/cydonia-24b-v4.1": { + "id": "TheDrummer 2/Cydonia-24B-v4.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 32768 + } + }, + "shisa-ai/shisa-v2.1-llama3.3-70b": { + "id": "shisa-ai/shisa-v2.1-llama3.3-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 4096 + } + }, + "shisa-ai/shisa-v2-llama3.3-70b": { + "id": "shisa-ai/shisa-v2-llama3.3-70b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "anthropic/claude-sonnet-4.6:thinking": { + "id": "anthropic/claude-sonnet-4.6:thinking", + "family": "claude-sonnet", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking:low": { + "id": "anthropic/claude-opus-4.6:thinking:low", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking": { + "id": "anthropic/claude-opus-4.6:thinking", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking:medium": { + "id": "anthropic/claude-opus-4.6:thinking:medium", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6:thinking:max": { + "id": "anthropic/claude-opus-4.6:thinking:max", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "miromind-ai/mirothinker-v1.5-235b": { + "id": "miromind-ai/MiroThinker-v1.5-235B", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 32768, + "output": 8192 + }, + "temperature": true + }, + "sao10k/l3.3-70b-euryale-v2.3": { + "id": "Sao10K/L3.3-70B-Euryale-v2.3", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + } + }, + "sao10k/l3.1-70b-euryale-v2.2": { + "id": "Sao10K/L3.1-70B-Euryale-v2.2", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20480, + "input": 20480, + "output": 16384 + } + }, + "huihui-ai/deepseek-r1-distill-llama-70b-abliterated": { + "id": "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated", + "family": "deepseek", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "huihui-ai/qwen2.5-32b-instruct-abliterated": { + "id": "huihui-ai/Qwen2.5-32B-Instruct-abliterated", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "huihui-ai/deepseek-r1-distill-qwen-32b-abliterated": { + "id": "huihui-ai/DeepSeek-R1-Distill-Qwen-32B-abliterated", + "family": "qwen", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "huihui-ai/llama-3.3-70b-instruct-abliterated": { + "id": "huihui-ai/Llama-3.3-70B-Instruct-abliterated", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "huihui-ai/llama-3.1-nemotron-70b-instruct-hf-abliterated": { + "id": "huihui-ai/Llama-3.1-Nemotron-70B-Instruct-HF-abliterated", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "dmind/dmind-1-mini": { + "id": "dmind/dmind-1-mini", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "dmind/dmind-1": { + "id": "dmind/dmind-1", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 8192 + } + }, + "eva-unit-01/eva-qwen2.5-72b-v0.2": { + "id": "EVA-UNIT-01/EVA-Qwen2.5-72B-v0.2", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "eva-unit-01/eva-llama-3.33-70b-v0.0": { + "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.0", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "eva-unit-01/eva-llama-3.33-70b-v0.1": { + "id": "EVA-UNIT-01/EVA-LLaMA-3.33-70B-v0.1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 16384 + } + }, + "eva-unit-01/eva-qwen2.5-32b-v0.2": { + "id": "EVA-UNIT-01/EVA-Qwen2.5-32B-v0.2", + "family": "qwen", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 8192 + } + }, + "qwen-3-235b-a22b-instruct-2507": { + "id": "qwen-3-235b-a22b-instruct-2507", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 32000 + } + }, + "llama3.1-8b": { + "id": "llama3.1-8b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8000 + } + }, + "zai-glm-4.7": { + "id": "zai-glm-4.7", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 40000 + } + }, + "gpt-5.3-chat": { + "id": "gpt-5.3-chat", + "family": "gpt-codex", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "kimi-k2-instruct": { + "id": "kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "claude-opus4-6": { + "id": "claude-opus4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "claude-4-6-sonnet": { + "id": "claude-4-6-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "devstral-small-2512": { + "id": "devstral-small-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "intellect-3": { + "id": "intellect-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nova-pro-v1": { + "id": "nova-pro-v1", + "family": "nova-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "output": 5000 + } + }, + "llama-3.1-405b-instruct": { + "id": "llama-3.1-405b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "claude-opus4-5": { + "id": "claude-opus4-5", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "claude-4-5-sonnet": { + "id": "claude-4-5-sonnet", + "family": "claude-sonnet", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 200000 + } + }, + "grok-2-1212": { + "id": "grok-2-1212", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4.20-multi-agent-0309": { + "id": "grok-4.20-multi-agent-0309", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-2": { + "id": "grok-2", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-3-fast-latest": { + "id": "grok-3-fast-latest", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-2-vision": { + "id": "grok-2-vision", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-2-vision-1212": { + "id": "grok-2-vision-1212", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-beta": { + "id": "grok-beta", + "family": "grok-beta", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 4096 + } + }, + "grok-3-mini-fast": { + "id": "grok-3-mini-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4-fast": { + "id": "grok-4-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-3-latest": { + "id": "grok-3-latest", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4-1-fast": { + "id": "grok-4-1-fast", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-2-vision-latest": { + "id": "grok-2-vision-latest", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-3-mini-latest": { + "id": "grok-3-mini-latest", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-3-mini-fast-latest": { + "id": "grok-3-mini-fast-latest", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4.20-0309-reasoning": { + "id": "grok-4.20-0309-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-2-latest": { + "id": "grok-2-latest", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-vision-beta": { + "id": "grok-vision-beta", + "family": "grok-vision", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096 + } + }, + "grok-4.20-0309-non-reasoning": { + "id": "grok-4.20-0309-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "grok-3-fast": { + "id": "grok-3-fast", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-math-plus": { + "id": "qwen-math-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "deepseek-v3-1": { + "id": "deepseek-v3-1", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "qwen2-5-coder-7b-instruct": { + "id": "qwen2-5-coder-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "deepseek-r1-distill-qwen-14b": { + "id": "deepseek-r1-distill-qwen-14b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "moonshot-kimi-k2-instruct": { + "id": "moonshot-kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen-doc-turbo": { + "id": "qwen-doc-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "tongyi-intent-detect-v3": { + "id": "tongyi-intent-detect-v3", + "family": "yi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1024 + } + }, + "qwen-plus-character": { + "id": "qwen-plus-character", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "deepseek-v3-2-exp": { + "id": "deepseek-v3-2-exp", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek-r1-distill-llama-8b": { + "id": "deepseek-r1-distill-llama-8b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "qwen3.5-flash": { + "id": "qwen3.5-flash", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen2-5-math-7b-instruct": { + "id": "qwen2-5-math-7b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "deepseek-r1-distill-qwen-1-5b": { + "id": "deepseek-r1-distill-qwen-1-5b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "deepseek-r1-distill-qwen-7b": { + "id": "deepseek-r1-distill-qwen-7b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 16384 + } + }, + "qwen-deep-research": { + "id": "qwen-deep-research", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32768 + } + }, + "qwen2-5-math-72b-instruct": { + "id": "qwen2-5-math-72b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "qwen-math-turbo": { + "id": "qwen-math-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 3072 + } + }, + "qwen2-5-coder-32b-instruct": { + "id": "qwen2-5-coder-32b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "kimi/kimi-k2.5": { + "id": "kimi/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "siliconflow/deepseek-r1-0528": { + "id": "siliconflow/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 32768 + } + }, + "siliconflow/deepseek-v3-0324": { + "id": "siliconflow/deepseek-v3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "siliconflow/deepseek-v3.1-terminus": { + "id": "siliconflow/deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "siliconflow/deepseek-v3.2": { + "id": "siliconflow/deepseek-v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "zai-org/glm-4.7-tee": { + "id": "zai-org/GLM-4.7-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.6-tee": { + "id": "zai-org/GLM-4.6-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65536 + } + }, + "zai-org/glm-5-tee": { + "id": "zai-org/GLM-5-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.6-fp8": { + "id": "zai-org/GLM-4.6-FP8", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "zai-org/glm-4.5-tee": { + "id": "zai-org/GLM-4.5-TEE", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "zai-org/glm-5-turbo": { + "id": "zai-org/GLM-5-Turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "nvidia/nvidia-nemotron-3-nano-30b-a3b-bf16": { + "id": "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16", + "family": "nemotron", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "nousresearch/hermes-4.3-36b": { + "id": "NousResearch/Hermes-4.3-36B", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "nousresearch/deephermes-3-mistral-24b-preview": { + "id": "NousResearch/DeepHermes-3-Mistral-24B-Preview", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "nousresearch/hermes-4-14b": { + "id": "NousResearch/Hermes-4-14B", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "nousresearch/hermes-4-405b-fp8-tee": { + "id": "NousResearch/Hermes-4-405B-FP8-TEE", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "minimaxai/minimax-m2.5-tee": { + "id": "MiniMaxAI/MiniMax-M2.5-TEE", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "minimaxai/minimax-m2.1-tee": { + "id": "MiniMaxAI/MiniMax-M2.1-TEE", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.1-terminus-tee": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-tee": { + "id": "deepseek-ai/DeepSeek-V3.2-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3-0324-tee": { + "id": "deepseek-ai/DeepSeek-V3-0324-TEE", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-v3.2-speciale-tee": { + "id": "deepseek-ai/DeepSeek-V3.2-Speciale-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-r1-tee": { + "id": "deepseek-ai/DeepSeek-R1-TEE", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "deepseek-ai/deepseek-v3.1-tee": { + "id": "deepseek-ai/DeepSeek-V3.1-TEE", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "deepseek-ai/deepseek-r1-0528-tee": { + "id": "deepseek-ai/DeepSeek-R1-0528-TEE", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "rednote-hilab/dots.ocr": { + "id": "rednote-hilab/dots.ocr", + "family": "rednote", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "unsloth/mistral-nemo-instruct-2407": { + "id": "unsloth/Mistral-Nemo-Instruct-2407", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "unsloth/mistral-small-24b-instruct-2501": { + "id": "unsloth/Mistral-Small-24B-Instruct-2501", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "unsloth/llama-3.2-1b-instruct": { + "id": "unsloth/Llama-3.2-1B-Instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "unsloth/llama-3.2-3b-instruct": { + "id": "unsloth/Llama-3.2-3B-Instruct", + "family": "unsloth", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "moonshotai/kimi-k2.5-tee": { + "id": "moonshotai/Kimi-K2.5-TEE", + "family": "kimi", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65535 + } + }, + "moonshotai/kimi-k2-thinking-tee": { + "id": "moonshotai/Kimi-K2-Thinking-TEE", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65535 + } + }, + "qwen/qwen3.5-397b-a17b-tee": { + "id": "Qwen/Qwen3.5-397B-A17B-TEE", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen3-coder-480b-a35b-instruct-fp8-tee": { + "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3-235b-a22b-instruct-2507-tee": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "qwen/qwen2.5-vl-72b-instruct-tee": { + "id": "Qwen/Qwen2.5-VL-72B-Instruct-TEE", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen/qwen3guard-gen-0.6b": { + "id": "Qwen/Qwen3Guard-Gen-0.6B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "tngtech/deepseek-r1t-chimera": { + "id": "tngtech/DeepSeek-R1T-Chimera", + "family": "tngtech", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "tngtech/tng-r1t-chimera-turbo": { + "id": "tngtech/TNG-R1T-Chimera-Turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "tngtech/tng-r1t-chimera-tee": { + "id": "tngtech/TNG-R1T-Chimera-TEE", + "family": "tngtech", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "mistralai/devstral-2-123b-instruct-2512-tee": { + "id": "mistralai/Devstral-2-123B-Instruct-2512-TEE", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "openai/gpt-oss-120b-tee": { + "id": "openai/gpt-oss-120b-TEE", + "family": "gpt-oss", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "chutesai/mistral-small-3.1-24b-instruct-2503": { + "id": "chutesai/Mistral-Small-3.1-24B-Instruct-2503", + "family": "chutesai", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "opengvlab/internvl3-78b-tee": { + "id": "OpenGVLab/InternVL3-78B-TEE", + "family": "opengvlab", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + } + } +} diff --git a/src/hooks/atlas/session-last-agent.sqlite.test.ts b/src/hooks/atlas/session-last-agent.sqlite.test.ts index 8501223b6..036482db5 100644 --- a/src/hooks/atlas/session-last-agent.sqlite.test.ts +++ b/src/hooks/atlas/session-last-agent.sqlite.test.ts @@ -1,8 +1,14 @@ const { describe, expect, mock, test } = require("bun:test") -mock.module("../../shared", () => ({ +mock.module("../../shared/opencode-message-dir", () => ({ getMessageDir: () => null, +})) + +mock.module("../../shared/opencode-storage-detection", () => ({ isSqliteBackend: () => true, +})) + +mock.module("../../shared/normalize-sdk-response", () => ({ normalizeSDKResponse: (response: { data?: TData }, fallback: TData): TData => response.data ?? fallback, })) diff --git a/src/hooks/auto-slash-command/processed-command-store.ts b/src/hooks/auto-slash-command/processed-command-store.ts index 2f6d86949..94e69428d 100644 --- a/src/hooks/auto-slash-command/processed-command-store.ts +++ b/src/hooks/auto-slash-command/processed-command-store.ts @@ -1,25 +1,36 @@ const MAX_PROCESSED_ENTRY_COUNT = 10_000 const PROCESSED_COMMAND_TTL_MS = 30_000 -function pruneExpiredEntries(entries: Map, now: number): Map { - return new Map(Array.from(entries.entries()).filter(([, expiresAt]) => expiresAt > now)) +function pruneExpiredEntries(entries: Map, now: number): void { + for (const [commandKey, expiresAt] of entries) { + if (expiresAt <= now) { + entries.delete(commandKey) + } + } } -function trimProcessedEntries(entries: Map): Map { +function trimProcessedEntries(entries: Map): void { if (entries.size <= MAX_PROCESSED_ENTRY_COUNT) { - return entries + return } - return new Map( - Array.from(entries.entries()) - .sort((left, right) => left[1] - right[1]) - .slice(Math.floor(entries.size / 2)) - ) + const targetSize = Math.floor(entries.size / 2) + for (const commandKey of entries.keys()) { + if (entries.size <= targetSize) { + return + } + + entries.delete(commandKey) + } } -function removeSessionEntries(entries: Map, sessionID: string): Map { +function removeSessionEntries(entries: Map, sessionID: string): void { const sessionPrefix = `${sessionID}:` - return new Map(Array.from(entries.entries()).filter(([entry]) => !entry.startsWith(sessionPrefix))) + for (const entry of entries.keys()) { + if (entry.startsWith(sessionPrefix)) { + entries.delete(entry) + } + } } export interface ProcessedCommandStore { @@ -34,19 +45,27 @@ export function createProcessedCommandStore(): ProcessedCommandStore { return { has(commandKey: string): boolean { - const now = Date.now() - entries = pruneExpiredEntries(entries, now) - return entries.has(commandKey) + const expiresAt = entries.get(commandKey) + if (expiresAt === undefined) { + return false + } + + if (expiresAt <= Date.now()) { + entries.delete(commandKey) + return false + } + + return true }, add(commandKey: string, ttlMs = PROCESSED_COMMAND_TTL_MS): void { const now = Date.now() - entries = pruneExpiredEntries(entries, now) + pruneExpiredEntries(entries, now) entries.delete(commandKey) entries.set(commandKey, now + ttlMs) - entries = trimProcessedEntries(entries) + trimProcessedEntries(entries) }, cleanupSession(sessionID: string): void { - entries = removeSessionEntries(entries, sessionID) + removeSessionEntries(entries, sessionID) }, clear(): void { entries.clear() diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts index 49391cc2b..6f2f06e2e 100644 --- a/src/hooks/auto-update-checker/hook.test.ts +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" const mockShowConfigErrorsIfAny = mock(async () => {}) const mockShowModelCacheWarningIfNeeded = mock(async () => {}) const mockUpdateAndShowConnectedProvidersCacheStatus = mock(async () => {}) +const mockRefreshModelCapabilitiesOnStartup = mock(async () => {}) const mockShowLocalDevToast = mock(async () => {}) const mockShowVersionToast = mock(async () => {}) const mockRunBackgroundUpdateCheck = mock(async () => {}) @@ -22,6 +23,10 @@ mock.module("./hook/connected-providers-status", () => ({ mockUpdateAndShowConnectedProvidersCacheStatus, })) +mock.module("./hook/model-capabilities-status", () => ({ + refreshModelCapabilitiesOnStartup: mockRefreshModelCapabilitiesOnStartup, +})) + mock.module("./hook/startup-toasts", () => ({ showLocalDevToast: mockShowLocalDevToast, showVersionToast: mockShowVersionToast, @@ -78,6 +83,7 @@ beforeEach(() => { mockShowConfigErrorsIfAny.mockClear() mockShowModelCacheWarningIfNeeded.mockClear() mockUpdateAndShowConnectedProvidersCacheStatus.mockClear() + mockRefreshModelCapabilitiesOnStartup.mockClear() mockShowLocalDevToast.mockClear() mockShowVersionToast.mockClear() mockRunBackgroundUpdateCheck.mockClear() @@ -112,6 +118,7 @@ describe("createAutoUpdateCheckerHook", () => { expect(mockShowConfigErrorsIfAny).not.toHaveBeenCalled() expect(mockShowModelCacheWarningIfNeeded).not.toHaveBeenCalled() expect(mockUpdateAndShowConnectedProvidersCacheStatus).not.toHaveBeenCalled() + expect(mockRefreshModelCapabilitiesOnStartup).not.toHaveBeenCalled() expect(mockShowLocalDevToast).not.toHaveBeenCalled() expect(mockShowVersionToast).not.toHaveBeenCalled() expect(mockRunBackgroundUpdateCheck).not.toHaveBeenCalled() @@ -129,6 +136,7 @@ describe("createAutoUpdateCheckerHook", () => { //#then - startup checks, toast, and background check run expect(mockShowConfigErrorsIfAny).toHaveBeenCalledTimes(1) expect(mockUpdateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mockRefreshModelCapabilitiesOnStartup).toHaveBeenCalledTimes(1) expect(mockShowModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) expect(mockShowVersionToast).toHaveBeenCalledTimes(1) expect(mockRunBackgroundUpdateCheck).toHaveBeenCalledTimes(1) @@ -146,6 +154,7 @@ describe("createAutoUpdateCheckerHook", () => { //#then - no startup actions run expect(mockShowConfigErrorsIfAny).not.toHaveBeenCalled() expect(mockUpdateAndShowConnectedProvidersCacheStatus).not.toHaveBeenCalled() + expect(mockRefreshModelCapabilitiesOnStartup).not.toHaveBeenCalled() expect(mockShowModelCacheWarningIfNeeded).not.toHaveBeenCalled() expect(mockShowLocalDevToast).not.toHaveBeenCalled() expect(mockShowVersionToast).not.toHaveBeenCalled() @@ -165,6 +174,7 @@ describe("createAutoUpdateCheckerHook", () => { //#then - side effects execute only once expect(mockShowConfigErrorsIfAny).toHaveBeenCalledTimes(1) expect(mockUpdateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mockRefreshModelCapabilitiesOnStartup).toHaveBeenCalledTimes(1) expect(mockShowModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) expect(mockShowVersionToast).toHaveBeenCalledTimes(1) expect(mockRunBackgroundUpdateCheck).toHaveBeenCalledTimes(1) @@ -183,6 +193,7 @@ describe("createAutoUpdateCheckerHook", () => { //#then - local dev toast is shown and background check is skipped expect(mockShowConfigErrorsIfAny).toHaveBeenCalledTimes(1) expect(mockUpdateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mockRefreshModelCapabilitiesOnStartup).toHaveBeenCalledTimes(1) expect(mockShowModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) expect(mockShowLocalDevToast).toHaveBeenCalledTimes(1) expect(mockShowVersionToast).not.toHaveBeenCalled() @@ -205,6 +216,7 @@ describe("createAutoUpdateCheckerHook", () => { //#then - no startup actions run expect(mockShowConfigErrorsIfAny).not.toHaveBeenCalled() expect(mockUpdateAndShowConnectedProvidersCacheStatus).not.toHaveBeenCalled() + expect(mockRefreshModelCapabilitiesOnStartup).not.toHaveBeenCalled() expect(mockShowModelCacheWarningIfNeeded).not.toHaveBeenCalled() expect(mockShowLocalDevToast).not.toHaveBeenCalled() expect(mockShowVersionToast).not.toHaveBeenCalled() diff --git a/src/hooks/auto-update-checker/hook.ts b/src/hooks/auto-update-checker/hook.ts index b915f9e55..caac8ddc5 100644 --- a/src/hooks/auto-update-checker/hook.ts +++ b/src/hooks/auto-update-checker/hook.ts @@ -5,11 +5,17 @@ import type { AutoUpdateCheckerOptions } from "./types" import { runBackgroundUpdateCheck } from "./hook/background-update-check" import { showConfigErrorsIfAny } from "./hook/config-errors-toast" import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status" +import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status" import { showModelCacheWarningIfNeeded } from "./hook/model-cache-warning" import { showLocalDevToast, showVersionToast } from "./hook/startup-toasts" export function createAutoUpdateCheckerHook(ctx: PluginInput, options: AutoUpdateCheckerOptions = {}) { - const { showStartupToast = true, isSisyphusEnabled = false, autoUpdate = true } = options + const { + showStartupToast = true, + isSisyphusEnabled = false, + autoUpdate = true, + modelCapabilities, + } = options const isCliRunMode = process.env.OPENCODE_CLI_RUN_MODE === "true" const getToastMessage = (isUpdate: boolean, latestVersion?: string): string => { @@ -43,6 +49,7 @@ export function createAutoUpdateCheckerHook(ctx: PluginInput, options: AutoUpdat await showConfigErrorsIfAny(ctx) await updateAndShowConnectedProvidersCacheStatus(ctx) + await refreshModelCapabilitiesOnStartup(modelCapabilities) await showModelCacheWarningIfNeeded(ctx) if (localDevVersion) { diff --git a/src/hooks/auto-update-checker/hook/model-capabilities-status.ts b/src/hooks/auto-update-checker/hook/model-capabilities-status.ts new file mode 100644 index 000000000..bead830b4 --- /dev/null +++ b/src/hooks/auto-update-checker/hook/model-capabilities-status.ts @@ -0,0 +1,37 @@ +import type { ModelCapabilitiesConfig } from "../../../config/schema/model-capabilities" +import { refreshModelCapabilitiesCache } from "../../../shared/model-capabilities-cache" +import { log } from "../../../shared/logger" + +const DEFAULT_REFRESH_TIMEOUT_MS = 5000 + +export async function refreshModelCapabilitiesOnStartup( + config: ModelCapabilitiesConfig | undefined, +): Promise { + if (config?.enabled === false) { + return + } + + if (config?.auto_refresh_on_start === false) { + return + } + + const timeoutMs = config?.refresh_timeout_ms ?? DEFAULT_REFRESH_TIMEOUT_MS + + let timeoutId: ReturnType | undefined + try { + await Promise.race([ + refreshModelCapabilitiesCache({ + sourceUrl: config?.source_url, + }), + new Promise((_, reject) => { + timeoutId = setTimeout(() => reject(new Error("Model capabilities refresh timed out")), timeoutMs) + }), + ]) + } catch (error) { + log("[auto-update-checker] Model capabilities refresh failed", { error: String(error) }) + } finally { + if (timeoutId) { + clearTimeout(timeoutId) + } + } +} diff --git a/src/hooks/auto-update-checker/types.ts b/src/hooks/auto-update-checker/types.ts index 550e5137f..460970f67 100644 --- a/src/hooks/auto-update-checker/types.ts +++ b/src/hooks/auto-update-checker/types.ts @@ -1,3 +1,5 @@ +import type { ModelCapabilitiesConfig } from "../../config/schema/model-capabilities" + export interface NpmDistTags { latest: string [key: string]: string @@ -26,4 +28,5 @@ export interface AutoUpdateCheckerOptions { showStartupToast?: boolean isSisyphusEnabled?: boolean autoUpdate?: boolean + modelCapabilities?: ModelCapabilitiesConfig } diff --git a/src/hooks/context-window-monitor.model-context-limits.test.ts b/src/hooks/context-window-monitor.model-context-limits.test.ts index 6dca2df5f..919050120 100644 --- a/src/hooks/context-window-monitor.model-context-limits.test.ts +++ b/src/hooks/context-window-monitor.model-context-limits.test.ts @@ -135,9 +135,96 @@ describe("context-window-monitor modelContextLimitsCache", () => { }) }) - describe("#given Anthropic provider with cached context limit and 1M mode disabled", () => { - describe("#when cached usage exceeds the Anthropic default limit", () => { - it("#then should ignore the cached limit and append the reminder from the default Anthropic limit", async () => { + describe("#given Anthropic 4.6 provider with cached context limit and 1M mode disabled", () => { + describe("#when cached usage is below threshold of cached limit", () => { + it("#then should respect the cached limit and skip the reminder", async () => { + // given + const modelContextLimitsCache = new Map() + modelContextLimitsCache.set("anthropic/claude-sonnet-4-6", 500000) + + const hook = createContextWindowMonitorHook({} as never, { + anthropicContext1MEnabled: false, + modelContextLimitsCache, + }) + const sessionID = "ses_anthropic_cached_limit_respected" + + await hook.event({ + event: { + type: "message.updated", + properties: { + info: { + role: "assistant", + sessionID, + providerID: "anthropic", + modelID: "claude-sonnet-4-6", + finish: true, + tokens: { + input: 150000, + output: 0, + reasoning: 0, + cache: { read: 10000, write: 0 }, + }, + }, + }, + }, + }) + + // when + const output = createOutput() + await hook["tool.execute.after"]({ tool: "bash", sessionID, callID: "call_1" }, output) + + // then — 160K/500K = 32%, well below 70% threshold + expect(output.output).toBe("original") + }) + }) + + describe("#when cached usage exceeds threshold of cached limit", () => { + it("#then should use the cached limit for the reminder", async () => { + // given + const modelContextLimitsCache = new Map() + modelContextLimitsCache.set("anthropic/claude-sonnet-4-6", 500000) + + const hook = createContextWindowMonitorHook({} as never, { + anthropicContext1MEnabled: false, + modelContextLimitsCache, + }) + const sessionID = "ses_anthropic_cached_limit_exceeded" + + await hook.event({ + event: { + type: "message.updated", + properties: { + info: { + role: "assistant", + sessionID, + providerID: "anthropic", + modelID: "claude-sonnet-4-6", + finish: true, + tokens: { + input: 350000, + output: 0, + reasoning: 0, + cache: { read: 10000, write: 0 }, + }, + }, + }, + }, + }) + + // when + const output = createOutput() + await hook["tool.execute.after"]({ tool: "bash", sessionID, callID: "call_1" }, output) + + // then — 360K/500K = 72%, above 70% threshold, uses cached 500K limit + expect(output.output).toContain("context remaining") + expect(output.output).toContain("500,000-token context window") + }) + }) + }) + + describe("#given older Anthropic provider with cached context limit and 1M mode disabled", () => { + describe("#when cached usage would only exceed the incorrect cached limit", () => { + it("#then should ignore the cached limit and use the 200K default", async () => { // given const modelContextLimitsCache = new Map() modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 500000) @@ -146,7 +233,7 @@ describe("context-window-monitor modelContextLimitsCache", () => { anthropicContext1MEnabled: false, modelContextLimitsCache, }) - const sessionID = "ses_anthropic_default_overrides_cached_limit" + const sessionID = "ses_anthropic_older_model_ignores_cached_limit" await hook.event({ event: { @@ -176,8 +263,6 @@ describe("context-window-monitor modelContextLimitsCache", () => { // then expect(output.output).toContain("context remaining") expect(output.output).toContain("200,000-token context window") - expect(output.output).not.toContain("500,000-token context window") - expect(output.output).not.toContain("1,000,000-token context window") }) }) }) diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 92f630906..09757ab3f 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -3,6 +3,24 @@ const { beforeEach, describe, expect, mock, test } = require("bun:test") const readConnectedProvidersCacheMock = mock(() => null) const readProviderModelsCacheMock = mock(() => null) +const selectFallbackProviderMock = mock((providers: string[], preferredProviderID?: string) => { + const connectedProviders = readConnectedProvidersCacheMock() + if (connectedProviders) { + const connectedSet = new Set(connectedProviders.map((provider: string) => provider.toLowerCase())) + + for (const provider of providers) { + if (connectedSet.has(provider.toLowerCase())) { + return provider + } + } + + if (preferredProviderID && connectedSet.has(preferredProviderID.toLowerCase())) { + return preferredProviderID + } + } + + return providers[0] || preferredProviderID || "opencode" +}) const transformModelForProviderMock = mock((provider: string, model: string) => { if (provider === "github-copilot") { return model @@ -31,6 +49,10 @@ mock.module("../../shared/provider-model-id-transform", () => ({ transformModelForProvider: transformModelForProviderMock, })) +mock.module("../../shared/model-error-classifier", () => ({ + selectFallbackProvider: selectFallbackProviderMock, +})) + import { clearPendingModelFallback, createModelFallbackHook, @@ -44,6 +66,7 @@ describe("model fallback hook", () => { readProviderModelsCacheMock.mockReturnValue(null) readConnectedProvidersCacheMock.mockClear() readProviderModelsCacheMock.mockClear() + selectFallbackProviderMock.mockClear() clearPendingModelFallback("ses_model_fallback_main") clearPendingModelFallback("ses_model_fallback_ghcp") diff --git a/src/hooks/model-fallback/hook.ts b/src/hooks/model-fallback/hook.ts index 045bba2df..cbbcbc935 100644 --- a/src/hooks/model-fallback/hook.ts +++ b/src/hooks/model-fallback/hook.ts @@ -274,3 +274,13 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie }, } } + +/** + * Resets all module-global state for testing. + * Clears pending fallbacks, toast keys, and session chains. + */ +export function _resetForTesting(): void { + pendingModelFallbacks.clear() + lastToastKey.clear() + sessionFallbackChains.clear() +} diff --git a/src/hooks/runtime-fallback/constants.ts b/src/hooks/runtime-fallback/constants.ts index 3f011b333..3bd4409a4 100644 --- a/src/hooks/runtime-fallback/constants.ts +++ b/src/hooks/runtime-fallback/constants.ts @@ -11,7 +11,7 @@ import type { RuntimeFallbackConfig } from "../../config" */ export const DEFAULT_CONFIG: Required = { enabled: false, - retry_on_errors: [429, 500, 502, 503, 504], + retry_on_errors: [402, 429, 500, 502, 503, 504], max_fallback_attempts: 3, cooldown_seconds: 60, timeout_seconds: 30, @@ -37,6 +37,11 @@ export const RETRYABLE_ERROR_PATTERNS = [ /try.?again/i, /credit.*balance.*too.*low/i, /insufficient.?(?:credits?|funds?|balance)/i, + /subscription.*quota/i, + /billing.?(?:hard.?)?limit/i, + /payment.?required/i, + /out\s+of\s+credits?/i, + /(?:^|\s)402(?:\s|$)/, /(?:^|\s)429(?:\s|$)/, /(?:^|\s)503(?:\s|$)/, /(?:^|\s)529(?:\s|$)/, diff --git a/src/hooks/runtime-fallback/error-classifier.test.ts b/src/hooks/runtime-fallback/error-classifier.test.ts index 954e28758..01bfe3d3e 100644 --- a/src/hooks/runtime-fallback/error-classifier.test.ts +++ b/src/hooks/runtime-fallback/error-classifier.test.ts @@ -31,6 +31,20 @@ describe("runtime-fallback error classifier", () => { expect(signal).toBeDefined() }) + test("detects too-many-requests auto-retry status signals without countdown text", () => { + //#given + const info = { + status: + "Too Many Requests: Sorry, you've exhausted this model's rate limit. Please try a different model.", + } + + //#when + const signal = extractAutoRetrySignal(info) + + //#then + expect(signal).toBeDefined() + }) + test("treats cooling-down retry messages as retryable", () => { //#given const error = { @@ -166,3 +180,100 @@ describe("extractStatusCode", () => { expect(extractStatusCode(error)).toBe(400) }) }) + +describe("quota error detection (fixes #2747)", () => { + test("classifies prettified subscription quota error as quota_exceeded", () => { + //#given + const error = { + name: "AI_APICallError", + message: "Subscription quota exceeded. You can continue using free models.", + } + + //#when + const errorType = classifyErrorType(error) + const retryable = isRetryableError(error, [402, 429, 500, 502, 503, 504]) + + //#then + expect(errorType).toBe("quota_exceeded") + expect(retryable).toBe(true) + }) + + test("classifies billing hard limit error as quota_exceeded", () => { + //#given + const error = { message: "You have reached your billing hard limit." } + + //#when + const errorType = classifyErrorType(error) + + //#then + expect(errorType).toBe("quota_exceeded") + }) + + test("classifies exhausted capacity error as quota_exceeded", () => { + //#given + const error = { message: "You have exhausted your capacity on this model." } + + //#when + const errorType = classifyErrorType(error) + + //#then + expect(errorType).toBe("quota_exceeded") + }) + + test("classifies out of credits error as quota_exceeded", () => { + //#given + const error = { message: "Out of credits. Please add more credits to continue." } + + //#when + const errorType = classifyErrorType(error) + + //#then + expect(errorType).toBe("quota_exceeded") + }) + + test("treats HTTP 402 Payment Required as retryable", () => { + //#given + const error = { statusCode: 402, message: "Payment Required" } + + //#when + const retryable = isRetryableError(error, [402, 429, 500, 502, 503, 504]) + + //#then + expect(retryable).toBe(true) + }) + + test("matches subscription quota pattern in RETRYABLE_ERROR_PATTERNS", () => { + //#given + const error = { message: "Subscription quota exceeded. You can continue using free models." } + + //#when + const retryable = isRetryableError(error, [429, 503]) + + //#then + expect(retryable).toBe(true) + }) + + test("classifies QuotaExceededError by errorName even without quota keywords in message", () => { + //#given + const error = { name: "QuotaExceededError", message: "Request failed." } + + //#when + const errorType = classifyErrorType(error) + + //#then + expect(errorType).toBe("quota_exceeded") + }) + + test("detects payment required errors as retryable", () => { + //#given + const error = { message: "Error 402: payment required for this request" } + + //#when + const errorType = classifyErrorType(error) + const retryable = isRetryableError(error, [429, 503]) + + //#then + expect(errorType).toBe("quota_exceeded") + expect(retryable).toBe(true) + }) +}) diff --git a/src/hooks/runtime-fallback/error-classifier.ts b/src/hooks/runtime-fallback/error-classifier.ts index e581f3fb8..e625ded0a 100644 --- a/src/hooks/runtime-fallback/error-classifier.ts +++ b/src/hooks/runtime-fallback/error-classifier.ts @@ -21,6 +21,13 @@ export function getErrorMessage(error: unknown): string { } } + const errorObj2 = error as Record + const name = errorObj2.name + if (typeof name === "string" && name.length > 0) { + const nameColonMatch = name.match(/:\s*(.+)/) + if (nameColonMatch) return nameColonMatch[1].trim().toLowerCase() + } + try { return JSON.stringify(error).toLowerCase() } catch { @@ -112,6 +119,21 @@ export function classifyErrorType(error: unknown): string | undefined { return "model_not_found" } + if ( + errorName?.includes("quotaexceeded") || + errorName?.includes("insufficientquota") || + errorName?.includes("billingerror") || + /quota.?exceeded/i.test(message) || + /subscription.*quota/i.test(message) || + /insufficient.?quota/i.test(message) || + /billing.?(?:hard.?)?limit/i.test(message) || + /exhausted\s+your\s+capacity/i.test(message) || + /out\s+of\s+credits?/i.test(message) || + /payment.?required/i.test(message) + ) { + return "quota_exceeded" + } + return undefined } @@ -145,7 +167,7 @@ export function extractAutoRetrySignal(info: Record | undefined const combined = candidates.join("\n") if (!combined) return undefined - const isAutoRetry = AUTO_RETRY_PATTERNS.every((test) => test(combined)) + const isAutoRetry = AUTO_RETRY_PATTERNS.some((test) => test(combined)) if (isAutoRetry) { return { signal: combined } } @@ -181,6 +203,10 @@ export function isRetryableError(error: unknown, retryOnErrors: number[]): boole return true } + if (errorType === "quota_exceeded") { + return true + } + if (statusCode && retryOnErrors.includes(statusCode)) { return true } diff --git a/src/hooks/runtime-fallback/message-update-handler.test.ts b/src/hooks/runtime-fallback/message-update-handler.test.ts index 7a3142e68..52a91abbe 100644 --- a/src/hooks/runtime-fallback/message-update-handler.test.ts +++ b/src/hooks/runtime-fallback/message-update-handler.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "bun:test" import type { RuntimeFallbackPluginInput } from "./types" import { hasVisibleAssistantResponse } from "./visible-assistant-response" +import { extractAutoRetrySignal } from "./error-classifier" function createContext(messagesResponse: unknown): RuntimeFallbackPluginInput { return { @@ -53,4 +54,29 @@ describe("hasVisibleAssistantResponse", () => { // then expect(result).toBe(true) }) + + it("#given a too-many-requests assistant reply #when visibility is checked #then it is treated as an auto-retry signal", async () => { + // given + const checkVisibleResponse = hasVisibleAssistantResponse(extractAutoRetrySignal) + const ctx = createContext({ + data: [ + { info: { role: "user" }, parts: [{ type: "text", text: "latest question" }] }, + { + info: { role: "assistant" }, + parts: [ + { + type: "text", + text: "Too Many Requests: Sorry, you've exhausted this model's rate limit. Please try a different model.", + }, + ], + }, + ], + }) + + // when + const result = await checkVisibleResponse(ctx, "session-rate-limit", undefined) + + // then + expect(result).toBe(false) + }) }) diff --git a/src/hooks/session-recovery/recover-tool-result-missing.test.ts b/src/hooks/session-recovery/recover-tool-result-missing.test.ts new file mode 100644 index 000000000..eac10fdd4 --- /dev/null +++ b/src/hooks/session-recovery/recover-tool-result-missing.test.ts @@ -0,0 +1,134 @@ +const { describe, it, expect, mock, beforeEach } = require("bun:test") + +import type { MessageData } from "./types" + +let sqliteBackend = false +let storedParts: Array<{ type: string; id?: string; callID?: string; [key: string]: unknown }> = [] + +mock.module("../../shared/opencode-storage-detection", () => ({ + isSqliteBackend: () => sqliteBackend, +})) + +mock.module("../../shared", () => ({ + normalizeSDKResponse: (response: { data?: TData }, fallback: TData): TData => response.data ?? fallback, +})) + +mock.module("./storage", () => ({ + readParts: () => storedParts, +})) + +const { recoverToolResultMissing } = await import("./recover-tool-result-missing") + +function createMockClient(messages: MessageData[] = []) { + const promptAsync = mock(() => Promise.resolve({})) + + return { + client: { + session: { + messages: mock(() => Promise.resolve({ data: messages })), + promptAsync, + }, + } as never, + promptAsync, + } +} + +const failedAssistantMsg: MessageData = { + info: { id: "msg_failed", role: "assistant" }, + parts: [], +} + +describe("recoverToolResultMissing", () => { + beforeEach(() => { + sqliteBackend = false + storedParts = [] + }) + + it("returns false for sqlite fallback when tool part has no valid callID", async () => { + //#given + sqliteBackend = true + const { client, promptAsync } = createMockClient([ + { + info: { id: "msg_failed", role: "assistant" }, + parts: [{ type: "tool", id: "prt_missing_call", name: "bash", input: {} }], + }, + ]) + + //#when + const result = await recoverToolResultMissing(client, "ses_1", failedAssistantMsg) + + //#then + expect(result).toBe(false) + expect(promptAsync).not.toHaveBeenCalled() + }) + + it("sends the recovered sqlite tool result when callID is valid", async () => { + //#given + sqliteBackend = true + const { client, promptAsync } = createMockClient([ + { + info: { id: "msg_failed", role: "assistant" }, + parts: [{ type: "tool", id: "prt_valid_call", callID: "call_recovered", name: "bash", input: {} }], + }, + ]) + + //#when + const result = await recoverToolResultMissing(client, "ses_1", failedAssistantMsg) + + //#then + expect(result).toBe(true) + expect(promptAsync).toHaveBeenCalledWith({ + path: { id: "ses_1" }, + body: { + parts: [{ + type: "tool_result", + tool_use_id: "call_recovered", + content: "Operation cancelled by user (ESC pressed)", + }], + }, + }) + }) + + it("returns false for stored parts when tool part has no valid callID", async () => { + //#given + storedParts = [{ type: "tool", id: "prt_stored_missing_call", tool: "bash", state: { input: {} } }] + const { client, promptAsync } = createMockClient() + + //#when + const result = await recoverToolResultMissing(client, "ses_2", failedAssistantMsg) + + //#then + expect(result).toBe(false) + expect(promptAsync).not.toHaveBeenCalled() + }) + + it("sends the recovered stored tool result when callID is valid", async () => { + //#given + storedParts = [{ + type: "tool", + id: "prt_stored_valid_call", + callID: "toolu_recovered", + tool: "bash", + state: { input: {} }, + }] + const { client, promptAsync } = createMockClient() + + //#when + const result = await recoverToolResultMissing(client, "ses_2", failedAssistantMsg) + + //#then + expect(result).toBe(true) + expect(promptAsync).toHaveBeenCalledWith({ + path: { id: "ses_2" }, + body: { + parts: [{ + type: "tool_result", + tool_use_id: "toolu_recovered", + content: "Operation cancelled by user (ESC pressed)", + }], + }, + }) + }) +}) + +export {} diff --git a/src/hooks/session-recovery/recover-tool-result-missing.ts b/src/hooks/session-recovery/recover-tool-result-missing.ts index 4d19880b3..c3d12da53 100644 --- a/src/hooks/session-recovery/recover-tool-result-missing.ts +++ b/src/hooks/session-recovery/recover-tool-result-missing.ts @@ -24,8 +24,30 @@ interface MessagePart { id?: string } +function isValidToolUseID(id: string | undefined): id is string { + return typeof id === "string" && /^(toolu_|call_)/.test(id) +} + +function normalizeMessagePart(part: { type: string; id?: string; callID?: string }): MessagePart | null { + if (part.type === "tool" || part.type === "tool_use") { + if (!isValidToolUseID(part.callID)) { + return null + } + + return { + type: "tool_use", + id: part.callID, + } + } + + return { + type: part.type, + id: part.id, + } +} + function extractToolUseIds(parts: MessagePart[]): string[] { - return parts.filter((part): part is ToolUsePart => part.type === "tool_use" && !!part.id).map((part) => part.id) + return parts.filter((part): part is ToolUsePart => part.type === "tool_use" && isValidToolUseID(part.id)).map((part) => part.id) } async function readPartsFromSDKFallback( @@ -39,10 +61,7 @@ async function readPartsFromSDKFallback( const target = messages.find((m) => m.info?.id === messageID) if (!target?.parts) return [] - return target.parts.map((part) => ({ - type: part.type === "tool" ? "tool_use" : part.type, - id: "callID" in part ? (part as { callID?: string }).callID : part.id, - })) + return target.parts.map((part) => normalizeMessagePart(part)).filter((part): part is MessagePart => part !== null) } catch { return [] } @@ -59,10 +78,7 @@ export async function recoverToolResultMissing( parts = await readPartsFromSDKFallback(client, sessionID, failedAssistantMsg.info.id) } else { const storedParts = readParts(failedAssistantMsg.info.id) - parts = storedParts.map((part) => ({ - type: part.type === "tool" ? "tool_use" : part.type, - id: "callID" in part ? (part as { callID?: string }).callID : part.id, - })) + parts = storedParts.map((part) => normalizeMessagePart(part)).filter((part): part is MessagePart => part !== null) } } diff --git a/src/hooks/thinking-block-validator/hook.test.ts b/src/hooks/thinking-block-validator/hook.test.ts index 9eab6dff6..0601cbcfc 100644 --- a/src/hooks/thinking-block-validator/hook.test.ts +++ b/src/hooks/thinking-block-validator/hook.test.ts @@ -1,108 +1,184 @@ -const { describe, expect, test } = require("bun:test") +declare const describe: (name: string, fn: () => void) => void +declare const it: (name: string, fn: () => void | Promise) => void +declare const expect: (value: T) => { + toBe(expected: T): void + toEqual(expected: unknown): void + toHaveLength(expected: number): void +} -const { createThinkingBlockValidatorHook } = require("./hook") +import { createThinkingBlockValidatorHook } from "./hook" type TestPart = { type: string - id: string text?: string thinking?: string - data?: string signature?: string + synthetic?: boolean } type TestMessage = { - info: { - role: string - id?: string - modelID?: string - } + info: { role: "assistant" | "user" } parts: TestPart[] } -function createMessage(info: TestMessage["info"], parts: TestPart[]): TestMessage { - return { info, parts } -} +async function runTransform(messages: TestMessage[]): Promise { + const hook = createThinkingBlockValidatorHook() + const transform = hook["experimental.chat.messages.transform"] -function createTextPart(id: string, text: string): TestPart { - return { type: "text", id, text } -} + if (!transform) { + throw new Error("missing thinking block validator transform") + } -function createSignedThinkingPart(id: string, thinking: string, signature: string): TestPart { - return { type: "thinking", id, thinking, signature } -} - -function createRedactedThinkingPart(id: string, signature: string): TestPart { - return { type: "redacted_thinking", id, data: "encrypted", signature } + await transform({}, { messages: messages as never }) } describe("createThinkingBlockValidatorHook", () => { - test("reuses the previous signed thinking part verbatim when assistant content lacks a leading thinking block", async () => { - const transform = Reflect.get(createThinkingBlockValidatorHook(), "experimental.chat.messages.transform") - expect(typeof transform).toBe("function") + it("injects signed thinking history verbatim", async () => { + //#given + const signedThinkingPart: TestPart = { + type: "thinking", + thinking: "plan", + signature: "signed-thinking", + } + const messages = [ + { + info: { role: "assistant" }, + parts: [signedThinkingPart], + }, + { + info: { role: "assistant" }, + parts: [{ type: "text", text: "continue" }], + }, + ] satisfies TestMessage[] - const previousThinkingPart = createSignedThinkingPart("prt_prev_signed", "prior reasoning", "sig_prev") - const targetTextPart = createTextPart("prt_target_text", "tool result") - const messages: TestMessage[] = [ - createMessage({ role: "user", modelID: "claude-opus-4-6-thinking" }, [createTextPart("prt_user_text", "continue")]), - createMessage({ role: "assistant", id: "msg_prev" }, [previousThinkingPart, createTextPart("prt_prev_text", "done")]), - createMessage({ role: "assistant", id: "msg_target" }, [targetTextPart]), - ] + //#when + await runTransform(messages) - await Reflect.apply(transform, undefined, [{}, { messages }]) - - expect(messages[2]?.parts[0]).toBe(previousThinkingPart) - expect(messages[2]?.parts).toEqual([previousThinkingPart, targetTextPart]) + //#then + expect(messages[1]?.parts[0]).toBe(signedThinkingPart) }) - test("skips injection when no signed Anthropic thinking part exists in history", async () => { - const transform = Reflect.get(createThinkingBlockValidatorHook(), "experimental.chat.messages.transform") - expect(typeof transform).toBe("function") + it("injects signed redacted_thinking history verbatim", async () => { + //#given + const signedRedactedThinkingPart: TestPart = { + type: "redacted_thinking", + signature: "signed-redacted-thinking", + } + const messages = [ + { + info: { role: "assistant" }, + parts: [signedRedactedThinkingPart], + }, + { + info: { role: "assistant" }, + parts: [{ type: "tool_use" }], + }, + ] satisfies TestMessage[] - const targetTextPart = createTextPart("prt_target_text", "tool result") - const messages: TestMessage[] = [ - createMessage({ role: "user", modelID: "claude-opus-4-6-thinking" }, [createTextPart("prt_user_text", "continue")]), - createMessage({ role: "assistant", id: "msg_prev" }, [{ type: "reasoning", id: "prt_reason", text: "gpt reasoning" }]), - createMessage({ role: "assistant", id: "msg_target" }, [targetTextPart]), - ] + //#when + await runTransform(messages) - await Reflect.apply(transform, undefined, [{}, { messages }]) - - expect(messages[2]?.parts).toEqual([targetTextPart]) + //#then + expect(messages[1]?.parts[0]).toBe(signedRedactedThinkingPart) }) - test("does not inject when the assistant message already starts with redacted thinking", async () => { - const transform = Reflect.get(createThinkingBlockValidatorHook(), "experimental.chat.messages.transform") - expect(typeof transform).toBe("function") + it("skips hook when history contains reasoning only", async () => { + //#given + const reasoningPart: TestPart = { + type: "reasoning", + text: "internal reasoning", + } + const messages = [ + { + info: { role: "assistant" }, + parts: [reasoningPart], + }, + { + info: { role: "assistant" }, + parts: [{ type: "text", text: "continue" }], + }, + ] satisfies TestMessage[] - const existingThinkingPart = createRedactedThinkingPart("prt_redacted", "sig_redacted") - const targetTextPart = createTextPart("prt_target_text", "tool result") - const messages: TestMessage[] = [ - createMessage({ role: "user", modelID: "claude-opus-4-6-thinking" }, [createTextPart("prt_user_text", "continue")]), - createMessage({ role: "assistant", id: "msg_target" }, [existingThinkingPart, targetTextPart]), - ] + //#when + await runTransform(messages) - await Reflect.apply(transform, undefined, [{}, { messages }]) - - expect(messages[1]?.parts).toEqual([existingThinkingPart, targetTextPart]) + //#then + expect(messages[1]?.parts).toEqual([{ type: "text", text: "continue" }]) }) - test("skips processing for models without extended thinking", async () => { - const transform = Reflect.get(createThinkingBlockValidatorHook(), "experimental.chat.messages.transform") - expect(typeof transform).toBe("function") + it("skips hook when no signed history exists", async () => { + //#given + const messages = [ + { + info: { role: "assistant" }, + parts: [{ type: "thinking", thinking: "draft" }], + }, + { + info: { role: "assistant" }, + parts: [{ type: "text", text: "continue" }], + }, + ] satisfies TestMessage[] - const previousThinkingPart = createSignedThinkingPart("prt_prev_signed", "prior reasoning", "sig_prev") - const targetTextPart = createTextPart("prt_target_text", "tool result") - const messages: TestMessage[] = [ - createMessage({ role: "user", modelID: "gpt-5.4" }, [createTextPart("prt_user_text", "continue")]), - createMessage({ role: "assistant", id: "msg_prev" }, [previousThinkingPart]), - createMessage({ role: "assistant", id: "msg_target" }, [targetTextPart]), - ] + //#when + await runTransform(messages) - await Reflect.apply(transform, undefined, [{}, { messages }]) + //#then + expect(messages[1]?.parts).toEqual([{ type: "text", text: "continue" }]) + }) - expect(messages[2]?.parts).toEqual([targetTextPart]) + it("skips hook when history contains synthetic signed blocks only", async () => { + //#given + const syntheticSignedPart: TestPart = { + type: "thinking", + thinking: "synthetic", + signature: "synthetic-signature", + synthetic: true, + } + const messages = [ + { + info: { role: "assistant" }, + parts: [syntheticSignedPart], + }, + { + info: { role: "assistant" }, + parts: [{ type: "text", text: "continue" }], + }, + ] satisfies TestMessage[] + + //#when + await runTransform(messages) + + //#then + expect(messages[1]?.parts).toEqual([{ type: "text", text: "continue" }]) + }) + + it("does not reinject when the message already starts with redacted_thinking", async () => { + //#given + const signedThinkingPart: TestPart = { + type: "thinking", + thinking: "plan", + signature: "signed-thinking", + } + const leadingRedactedThinkingPart: TestPart = { + type: "redacted_thinking", + signature: "existing-redacted-thinking", + } + const messages = [ + { + info: { role: "assistant" }, + parts: [signedThinkingPart], + }, + { + info: { role: "assistant" }, + parts: [leadingRedactedThinkingPart, { type: "text", text: "continue" }], + }, + ] satisfies TestMessage[] + + //#when + await runTransform(messages) + + //#then + expect(messages[1]?.parts[0]).toBe(leadingRedactedThinkingPart) + expect(messages[1]?.parts).toHaveLength(2) }) }) - -export {} diff --git a/src/hooks/thinking-block-validator/hook.ts b/src/hooks/thinking-block-validator/hook.ts index 67b6c12c0..544d8e672 100644 --- a/src/hooks/thinking-block-validator/hook.ts +++ b/src/hooks/thinking-block-validator/hook.ts @@ -21,11 +21,6 @@ interface MessageWithParts { parts: Part[] } -type SignedThinkingPart = Part & { - type: "thinking" | "redacted_thinking" - signature: string -} - type MessagesTransformHook = { "experimental.chat.messages.transform"?: ( input: Record, @@ -33,25 +28,39 @@ type MessagesTransformHook = { ) => Promise } -/** - * Check if a model has extended thinking enabled - * Uses patterns from think-mode/switcher.ts for consistency - */ -function isExtendedThinkingModel(modelID: string): boolean { - if (!modelID) return false - const lower = modelID.toLowerCase() +type SignedThinkingPart = Part & { + type: "thinking" | "redacted_thinking" + thinking?: string + signature: string + synthetic?: boolean +} - // Check for explicit thinking/high variants (always enabled) - if (lower.includes("thinking") || lower.endsWith("-high")) { - return true +function isSignedThinkingPart(part: Part): part is SignedThinkingPart { + const type = part.type as string + if (type !== "thinking" && type !== "redacted_thinking") { + return false } - // Check for thinking-capable models (claude-4 family, claude-3) - // Aligns with THINKING_CAPABLE_MODELS in think-mode/switcher.ts - return ( - lower.includes("claude-sonnet-4") || - lower.includes("claude-opus-4") || - lower.includes("claude-3") + const signature = (part as { signature?: unknown }).signature + const synthetic = (part as { synthetic?: unknown }).synthetic + return typeof signature === "string" && signature.length > 0 && synthetic !== true +} + +/** + * Check if there are any Anthropic-signed thinking blocks in the message history. + * + * Only returns true for real `type: "thinking"` blocks with a valid `signature`. + * GPT reasoning blocks (`type: "reasoning"`) are intentionally excluded — they + * have no Anthropic signature and must never be forwarded to the Anthropic API. + * + * Model-name checks are unreliable (miss GPT+thinking, custom model IDs, etc.) + * so we inspect the messages themselves. + */ +function hasSignedThinkingBlocksInHistory(messages: MessageWithParts[]): boolean { + return messages.some( + m => + m.info.role === "assistant" && + m.parts?.some((p: Part) => isSignedThinkingPart(p)), ) } @@ -79,36 +88,42 @@ function startsWithThinkingBlock(parts: Part[]): boolean { return type === "thinking" || type === "redacted_thinking" || type === "reasoning" } -function isSignedThinkingPart(part: Part): part is SignedThinkingPart { - const type = part.type as string - if (type !== "thinking" && type !== "redacted_thinking") { - return false - } - - const signature = (part as { signature?: unknown }).signature - return typeof signature === "string" && signature.length > 0 -} - -function findPreviousThinkingPart( - messages: MessageWithParts[], - currentIndex: number -): SignedThinkingPart | null { +/** + * Find the most recent Anthropic-signed thinking part from previous assistant messages. + * + * Returns the original Part object (including its `signature` field) so it can + * be reused verbatim in another message. Only `type: "thinking"` blocks with + * both a `signature` and `thinking` field are returned — GPT `type: "reasoning"` + * blocks are excluded because they lack an Anthropic signature and would be + * rejected by the API with "Invalid `signature` in `thinking` block". + * Synthetic parts injected by a previous run of this hook are also skipped. + */ +function findPreviousThinkingPart(messages: MessageWithParts[], currentIndex: number): SignedThinkingPart | null { // Search backwards from current message for (let i = currentIndex - 1; i >= 0; i--) { const msg = messages[i] if (msg.info.role !== "assistant") continue - if (!msg.parts) continue + for (const part of msg.parts) { - if (isSignedThinkingPart(part)) { - return part - } + // Only Anthropic thinking blocks — type must be "thinking", not "reasoning" + if (!isSignedThinkingPart(part)) continue + + return part } } return null } +/** + * Prepend an existing thinking block (with its original signature) to a + * message's parts array. + * + * We reuse the original Part verbatim instead of creating a new one, because + * the Anthropic API validates the `signature` field against the thinking + * content. Any synthetic block we create ourselves would fail that check. + */ function prependThinkingBlock(message: MessageWithParts, thinkingPart: SignedThinkingPart): void { if (!message.parts) { message.parts = [] @@ -129,13 +144,12 @@ export function createThinkingBlockValidatorHook(): MessagesTransformHook { return } - // Get the model info from the last user message - const lastUserMessage = messages.findLast(m => m.info.role === "user") - const modelIDValue = (lastUserMessage?.info as { modelID?: unknown } | undefined)?.modelID - const modelID = typeof modelIDValue === "string" ? modelIDValue : "" - - // Only process if extended thinking might be enabled - if (!isExtendedThinkingModel(modelID)) { + // Skip if there are no Anthropic-signed thinking blocks in history. + // This is more reliable than checking model names — works for Claude, + // GPT with thinking variants, or any future model. Crucially, GPT + // reasoning blocks (type="reasoning", no signature) do NOT trigger this + // hook — only real Anthropic thinking blocks do. + if (!hasSignedThinkingBlocksInHistory(messages)) { return } @@ -148,12 +162,18 @@ export function createThinkingBlockValidatorHook(): MessagesTransformHook { // Check if message has content parts but doesn't start with thinking if (hasContentParts(msg.parts) && !startsWithThinkingBlock(msg.parts)) { + // Find the most recent real thinking part (with valid signature) from + // previous turns. If none exists we cannot safely inject a thinking + // block — a synthetic block without a signature would cause the API + // to reject the request with "Invalid `signature` in `thinking` block". const previousThinkingPart = findPreviousThinkingPart(messages, i) - if (!previousThinkingPart) { - continue - } - prependThinkingBlock(msg, previousThinkingPart) + if (previousThinkingPart) { + prependThinkingBlock(msg, previousThinkingPart) + } + // If no real thinking part is available, skip injection entirely. + // The downstream error (if any) is preferable to a guaranteed API + // rejection caused by a signature-less synthetic thinking block. } } }, diff --git a/src/index.ts b/src/index.ts index 70156f109..506e65c35 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,7 @@ import { createPluginDispose, type PluginDispose } from "./plugin-dispose" import { loadPluginConfig } from "./plugin-config" import { createModelCacheState } from "./plugin-state" import { createFirstMessageVariantGate } from "./shared/first-message-variant" -import { injectServerAuthIntoClient, log } from "./shared" +import { injectServerAuthIntoClient, log, logLegacyPluginStartupWarning } from "./shared" import { startTmuxCheck } from "./tools" let activePluginDispose: PluginDispose | null = null @@ -23,6 +23,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { directory: ctx.directory, }) + logLegacyPluginStartupWarning() injectServerAuthIntoClient(ctx.client) startTmuxCheck() @@ -89,6 +90,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { activePluginDispose = dispose return { + name: "oh-my-openagent", ...pluginInterface, "experimental.session.compacting": async ( diff --git a/src/plugin-handlers/agent-config-handler-agents-skills.test.ts b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts new file mode 100644 index 000000000..593f22d9e --- /dev/null +++ b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts @@ -0,0 +1,125 @@ +import type { AgentConfig } from "@opencode-ai/sdk" +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test" +import * as agents from "../agents" +import * as shared from "../shared" +import * as sisyphusJunior from "../agents/sisyphus-junior" +import type { OhMyOpenCodeConfig } from "../config" +import * as skillLoader from "../features/opencode-skill-loader" +import { applyAgentConfig } from "./agent-config-handler" +import type { PluginComponents } from "./plugin-components-loader" + +function createPluginComponents(): PluginComponents { + return { + commands: {}, + skills: {}, + agents: {}, + mcpServers: {}, + hooksConfigs: [], + plugins: [], + errors: [], + } +} + +function createPluginConfig(): OhMyOpenCodeConfig { + return { + sisyphus_agent: { + planner_enabled: false, + }, + } +} + +describe("applyAgentConfig .agents skills", () => { + let createBuiltinAgentsSpy: ReturnType + let createSisyphusJuniorAgentSpy: ReturnType + let discoverConfigSourceSkillsSpy: ReturnType + let discoverUserClaudeSkillsSpy: ReturnType + let discoverProjectClaudeSkillsSpy: ReturnType + let discoverOpencodeGlobalSkillsSpy: ReturnType + let discoverOpencodeProjectSkillsSpy: ReturnType + let discoverProjectAgentsSkillsSpy: ReturnType + let discoverGlobalAgentsSkillsSpy: ReturnType + let logSpy: ReturnType + + beforeEach(() => { + createBuiltinAgentsSpy = spyOn(agents, "createBuiltinAgents").mockResolvedValue({ + sisyphus: { name: "sisyphus", prompt: "builtin", mode: "primary" } satisfies AgentConfig, + }) + createSisyphusJuniorAgentSpy = spyOn( + sisyphusJunior, + "createSisyphusJuniorAgentWithOverrides", + ).mockReturnValue({ + name: "sisyphus-junior", + prompt: "junior", + mode: "all", + } satisfies AgentConfig) + discoverConfigSourceSkillsSpy = spyOn(skillLoader, "discoverConfigSourceSkills").mockResolvedValue([]) + discoverUserClaudeSkillsSpy = spyOn(skillLoader, "discoverUserClaudeSkills").mockResolvedValue([]) + discoverProjectClaudeSkillsSpy = spyOn(skillLoader, "discoverProjectClaudeSkills").mockResolvedValue([]) + discoverOpencodeGlobalSkillsSpy = spyOn(skillLoader, "discoverOpencodeGlobalSkills").mockResolvedValue([]) + discoverOpencodeProjectSkillsSpy = spyOn(skillLoader, "discoverOpencodeProjectSkills").mockResolvedValue([]) + discoverProjectAgentsSkillsSpy = spyOn(skillLoader, "discoverProjectAgentsSkills").mockResolvedValue([]) + discoverGlobalAgentsSkillsSpy = spyOn(skillLoader, "discoverGlobalAgentsSkills").mockResolvedValue([]) + logSpy = spyOn(shared, "log").mockImplementation(() => {}) + }) + + afterEach(() => { + createBuiltinAgentsSpy.mockRestore() + createSisyphusJuniorAgentSpy.mockRestore() + discoverConfigSourceSkillsSpy.mockRestore() + discoverUserClaudeSkillsSpy.mockRestore() + discoverProjectClaudeSkillsSpy.mockRestore() + discoverOpencodeGlobalSkillsSpy.mockRestore() + discoverOpencodeProjectSkillsSpy.mockRestore() + discoverProjectAgentsSkillsSpy.mockRestore() + discoverGlobalAgentsSkillsSpy.mockRestore() + logSpy.mockRestore() + }) + + test("calls .agents skill discovery during agent configuration", async () => { + // given + const directory = "/tmp/project" + + // when + await applyAgentConfig({ + config: { model: "anthropic/claude-opus-4-6", agent: {} }, + pluginConfig: createPluginConfig(), + ctx: { directory }, + pluginComponents: createPluginComponents(), + }) + + // then + expect(discoverProjectAgentsSkillsSpy).toHaveBeenCalledWith(directory) + expect(discoverGlobalAgentsSkillsSpy).toHaveBeenCalled() + }) + + test("passes discovered .agents skills to builtin agent creation", async () => { + // given + discoverProjectAgentsSkillsSpy.mockResolvedValue([ + { + name: "project-agent-skill", + definition: { name: "project-agent-skill", template: "project-template" }, + scope: "project", + }, + ]) + discoverGlobalAgentsSkillsSpy.mockResolvedValue([ + { + name: "global-agent-skill", + definition: { name: "global-agent-skill", template: "global-template" }, + scope: "user", + }, + ]) + + // when + await applyAgentConfig({ + config: { model: "anthropic/claude-opus-4-6", agent: {} }, + pluginConfig: createPluginConfig(), + ctx: { directory: "/tmp/project" }, + pluginComponents: createPluginComponents(), + }) + + // then + const discoveredSkills = createBuiltinAgentsSpy.mock.calls[0]?.[6] as Array<{ name: string }> + expect(discoveredSkills.map(skill => skill.name)).toContain("project-agent-skill") + expect(discoveredSkills.map(skill => skill.name)).toContain("global-agent-skill") + }) +}) diff --git a/src/plugin-handlers/agent-config-handler.test.ts b/src/plugin-handlers/agent-config-handler.test.ts index d0d01a897..6cb7514ed 100644 --- a/src/plugin-handlers/agent-config-handler.test.ts +++ b/src/plugin-handlers/agent-config-handler.test.ts @@ -8,6 +8,7 @@ import * as sisyphusJunior from "../agents/sisyphus-junior" import type { OhMyOpenCodeConfig } from "../config" import * as agentLoader from "../features/claude-code-agent-loader" import * as skillLoader from "../features/opencode-skill-loader" +import type { LoadedSkill } from "../features/opencode-skill-loader" import { getAgentDisplayName } from "../shared/agent-display-names" import { applyAgentConfig } from "./agent-config-handler" import type { PluginComponents } from "./plugin-components-loader" @@ -51,6 +52,8 @@ describe("applyAgentConfig builtin override protection", () => { let discoverProjectClaudeSkillsSpy: ReturnType let discoverOpencodeGlobalSkillsSpy: ReturnType let discoverOpencodeProjectSkillsSpy: ReturnType + let discoverProjectAgentsSkillsSpy: ReturnType + let discoverGlobalAgentsSkillsSpy: ReturnType let loadUserAgentsSpy: ReturnType let loadProjectAgentsSpy: ReturnType let migrateAgentConfigSpy: ReturnType @@ -60,6 +63,7 @@ describe("applyAgentConfig builtin override protection", () => { name: "Builtin Sisyphus", prompt: "builtin prompt", mode: "primary", + order: 1, } const builtinOracleConfig: AgentConfig = { @@ -120,6 +124,14 @@ describe("applyAgentConfig builtin override protection", () => { skillLoader, "discoverOpencodeProjectSkills", ).mockResolvedValue([]) + discoverProjectAgentsSkillsSpy = spyOn( + skillLoader, + "discoverProjectAgentsSkills", + ).mockResolvedValue([]) + discoverGlobalAgentsSkillsSpy = spyOn( + skillLoader, + "discoverGlobalAgentsSkills", + ).mockResolvedValue([]) loadUserAgentsSpy = spyOn(agentLoader, "loadUserAgents").mockReturnValue({}) loadProjectAgentsSpy = spyOn(agentLoader, "loadProjectAgents").mockReturnValue({}) @@ -138,6 +150,8 @@ describe("applyAgentConfig builtin override protection", () => { discoverProjectClaudeSkillsSpy.mockRestore() discoverOpencodeGlobalSkillsSpy.mockRestore() discoverOpencodeProjectSkillsSpy.mockRestore() + discoverProjectAgentsSkillsSpy.mockRestore() + discoverGlobalAgentsSkillsSpy.mockRestore() loadUserAgentsSpy.mockRestore() loadProjectAgentsSpy.mockRestore() migrateAgentConfigSpy.mockRestore() @@ -278,4 +292,45 @@ describe("applyAgentConfig builtin override protection", () => { // then expect(createSisyphusJuniorAgentSpy).toHaveBeenCalledWith(undefined, "openai/gpt-5.4", false) }) + + test("includes project and global .agents skills in builtin agent awareness", async () => { + // given + const projectAgentsSkill = { + name: "project-agent-skill", + definition: { + name: "project-agent-skill", + description: "Project agent skill", + template: "template", + }, + scope: "project", + } satisfies LoadedSkill + const globalAgentsSkill = { + name: "global-agent-skill", + definition: { + name: "global-agent-skill", + description: "Global agent skill", + template: "template", + }, + scope: "user", + } satisfies LoadedSkill + discoverProjectAgentsSkillsSpy.mockResolvedValue([projectAgentsSkill]) + discoverGlobalAgentsSkillsSpy.mockResolvedValue([globalAgentsSkill]) + + // when + await applyAgentConfig({ + config: createBaseConfig(), + pluginConfig: createPluginConfig(), + ctx: { directory: "/tmp" }, + pluginComponents: createPluginComponents(), + }) + + // then + const discoveredSkills = createBuiltinAgentsSpy.mock.calls[0]?.[6] + expect(discoveredSkills).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "project-agent-skill" }), + expect.objectContaining({ name: "global-agent-skill" }), + ]), + ) + }) }) diff --git a/src/plugin-handlers/agent-config-handler.ts b/src/plugin-handlers/agent-config-handler.ts index 33f15f233..539fa6bb0 100644 --- a/src/plugin-handlers/agent-config-handler.ts +++ b/src/plugin-handlers/agent-config-handler.ts @@ -6,8 +6,10 @@ import { AGENT_NAME_MAP } from "../shared/migration"; import { getAgentDisplayName } from "../shared/agent-display-names"; import { discoverConfigSourceSkills, + discoverGlobalAgentsSkills, discoverOpencodeGlobalSkills, discoverOpencodeProjectSkills, + discoverProjectAgentsSkills, discoverProjectClaudeSkills, discoverUserClaudeSkills, } from "../features/opencode-skill-loader"; @@ -52,8 +54,10 @@ export async function applyAgentConfig(params: { discoveredConfigSourceSkills, discoveredUserSkills, discoveredProjectSkills, + discoveredProjectAgentsSkills, discoveredOpencodeGlobalSkills, discoveredOpencodeProjectSkills, + discoveredGlobalAgentsSkills, ] = await Promise.all([ discoverConfigSourceSkills({ config: params.pluginConfig.skills, @@ -63,16 +67,22 @@ export async function applyAgentConfig(params: { includeClaudeSkillsForAwareness ? discoverProjectClaudeSkills(params.ctx.directory) : Promise.resolve([]), + includeClaudeSkillsForAwareness + ? discoverProjectAgentsSkills(params.ctx.directory) + : Promise.resolve([]), discoverOpencodeGlobalSkills(), discoverOpencodeProjectSkills(params.ctx.directory), + includeClaudeSkillsForAwareness ? discoverGlobalAgentsSkills() : Promise.resolve([]), ]); const allDiscoveredSkills = [ ...discoveredConfigSourceSkills, ...discoveredOpencodeProjectSkills, ...discoveredProjectSkills, + ...discoveredProjectAgentsSkills, ...discoveredOpencodeGlobalSkills, ...discoveredUserSkills, + ...discoveredGlobalAgentsSkills, ]; const browserProvider = diff --git a/src/plugin-handlers/agent-priority-order.ts b/src/plugin-handlers/agent-priority-order.ts index 9ca886130..c315ad76a 100644 --- a/src/plugin-handlers/agent-priority-order.ts +++ b/src/plugin-handlers/agent-priority-order.ts @@ -1,11 +1,21 @@ import { getAgentDisplayName } from "../shared/agent-display-names"; -const CORE_AGENT_ORDER = [ - getAgentDisplayName("sisyphus"), - getAgentDisplayName("hephaestus"), - getAgentDisplayName("prometheus"), - getAgentDisplayName("atlas"), -] as const; +const CORE_AGENT_ORDER: ReadonlyArray<{ displayName: string; order: number }> = [ + { displayName: getAgentDisplayName("sisyphus"), order: 1 }, + { displayName: getAgentDisplayName("hephaestus"), order: 2 }, + { displayName: getAgentDisplayName("prometheus"), order: 3 }, + { displayName: getAgentDisplayName("atlas"), order: 4 }, +]; + +function injectOrderField( + agentConfig: unknown, + order: number, +): unknown { + if (typeof agentConfig === "object" && agentConfig !== null) { + return { ...agentConfig, order }; + } + return agentConfig; +} export function reorderAgentsByPriority( agents: Record, @@ -13,10 +23,10 @@ export function reorderAgentsByPriority( const ordered: Record = {}; const seen = new Set(); - for (const key of CORE_AGENT_ORDER) { - if (Object.prototype.hasOwnProperty.call(agents, key)) { - ordered[key] = agents[key]; - seen.add(key); + for (const { displayName, order } of CORE_AGENT_ORDER) { + if (Object.prototype.hasOwnProperty.call(agents, displayName)) { + ordered[displayName] = injectOrderField(agents[displayName], order); + seen.add(displayName); } } diff --git a/src/plugin-handlers/command-config-handler.test.ts b/src/plugin-handlers/command-config-handler.test.ts new file mode 100644 index 000000000..7767c6639 --- /dev/null +++ b/src/plugin-handlers/command-config-handler.test.ts @@ -0,0 +1,98 @@ +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; +import * as builtinCommands from "../features/builtin-commands"; +import * as commandLoader from "../features/claude-code-command-loader"; +import * as skillLoader from "../features/opencode-skill-loader"; +import type { OhMyOpenCodeConfig } from "../config"; +import type { PluginComponents } from "./plugin-components-loader"; +import { applyCommandConfig } from "./command-config-handler"; + +function createPluginComponents(): PluginComponents { + return { + commands: {}, + skills: {}, + agents: {}, + mcpServers: {}, + hooksConfigs: [], + plugins: [], + errors: [], + }; +} + +function createPluginConfig(): OhMyOpenCodeConfig { + return {}; +} + +describe("applyCommandConfig", () => { + let loadBuiltinCommandsSpy: ReturnType; + let loadUserCommandsSpy: ReturnType; + let loadProjectCommandsSpy: ReturnType; + let loadOpencodeGlobalCommandsSpy: ReturnType; + let loadOpencodeProjectCommandsSpy: ReturnType; + let discoverConfigSourceSkillsSpy: ReturnType; + let loadUserSkillsSpy: ReturnType; + let loadProjectSkillsSpy: ReturnType; + let loadOpencodeGlobalSkillsSpy: ReturnType; + let loadOpencodeProjectSkillsSpy: ReturnType; + let loadProjectAgentsSkillsSpy: ReturnType; + let loadGlobalAgentsSkillsSpy: ReturnType; + + beforeEach(() => { + loadBuiltinCommandsSpy = spyOn(builtinCommands, "loadBuiltinCommands").mockReturnValue({}); + loadUserCommandsSpy = spyOn(commandLoader, "loadUserCommands").mockResolvedValue({}); + loadProjectCommandsSpy = spyOn(commandLoader, "loadProjectCommands").mockResolvedValue({}); + loadOpencodeGlobalCommandsSpy = spyOn(commandLoader, "loadOpencodeGlobalCommands").mockResolvedValue({}); + loadOpencodeProjectCommandsSpy = spyOn(commandLoader, "loadOpencodeProjectCommands").mockResolvedValue({}); + discoverConfigSourceSkillsSpy = spyOn(skillLoader, "discoverConfigSourceSkills").mockResolvedValue([]); + loadUserSkillsSpy = spyOn(skillLoader, "loadUserSkills").mockResolvedValue({}); + loadProjectSkillsSpy = spyOn(skillLoader, "loadProjectSkills").mockResolvedValue({}); + loadOpencodeGlobalSkillsSpy = spyOn(skillLoader, "loadOpencodeGlobalSkills").mockResolvedValue({}); + loadOpencodeProjectSkillsSpy = spyOn(skillLoader, "loadOpencodeProjectSkills").mockResolvedValue({}); + loadProjectAgentsSkillsSpy = spyOn(skillLoader, "loadProjectAgentsSkills").mockResolvedValue({}); + loadGlobalAgentsSkillsSpy = spyOn(skillLoader, "loadGlobalAgentsSkills").mockResolvedValue({}); + }); + + afterEach(() => { + loadBuiltinCommandsSpy.mockRestore(); + loadUserCommandsSpy.mockRestore(); + loadProjectCommandsSpy.mockRestore(); + loadOpencodeGlobalCommandsSpy.mockRestore(); + loadOpencodeProjectCommandsSpy.mockRestore(); + discoverConfigSourceSkillsSpy.mockRestore(); + loadUserSkillsSpy.mockRestore(); + loadProjectSkillsSpy.mockRestore(); + loadOpencodeGlobalSkillsSpy.mockRestore(); + loadOpencodeProjectSkillsSpy.mockRestore(); + loadProjectAgentsSkillsSpy.mockRestore(); + loadGlobalAgentsSkillsSpy.mockRestore(); + }); + + test("includes .agents skills in command config", async () => { + // given + loadProjectAgentsSkillsSpy.mockResolvedValue({ + "agents-project-skill": { + description: "(project - Skill) Agents project skill", + template: "template", + }, + }); + loadGlobalAgentsSkillsSpy.mockResolvedValue({ + "agents-global-skill": { + description: "(user - Skill) Agents global skill", + template: "template", + }, + }); + const config: Record = { command: {} }; + + // when + await applyCommandConfig({ + config, + pluginConfig: createPluginConfig(), + ctx: { directory: "/tmp" }, + pluginComponents: createPluginComponents(), + }); + + // then + const commandConfig = config.command as Record; + expect(commandConfig["agents-project-skill"]?.description).toContain("Agents project skill"); + expect(commandConfig["agents-global-skill"]?.description).toContain("Agents global skill"); + }); +}); diff --git a/src/plugin-handlers/command-config-handler.ts b/src/plugin-handlers/command-config-handler.ts index a5cb0e946..7afd1e416 100644 --- a/src/plugin-handlers/command-config-handler.ts +++ b/src/plugin-handlers/command-config-handler.ts @@ -9,6 +9,8 @@ import { import { loadBuiltinCommands } from "../features/builtin-commands"; import { discoverConfigSourceSkills, + loadGlobalAgentsSkills, + loadProjectAgentsSkills, loadUserSkills, loadProjectSkills, loadOpencodeGlobalSkills, @@ -36,7 +38,9 @@ export async function applyCommandConfig(params: { opencodeGlobalCommands, opencodeProjectCommands, userSkills, + globalAgentsSkills, projectSkills, + projectAgentsSkills, opencodeGlobalSkills, opencodeProjectSkills, ] = await Promise.all([ @@ -49,7 +53,9 @@ export async function applyCommandConfig(params: { loadOpencodeGlobalCommands(), loadOpencodeProjectCommands(params.ctx.directory), includeClaudeSkills ? loadUserSkills() : Promise.resolve({}), + includeClaudeSkills ? loadGlobalAgentsSkills() : Promise.resolve({}), includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}), + includeClaudeSkills ? loadProjectAgentsSkills(params.ctx.directory) : Promise.resolve({}), loadOpencodeGlobalSkills(), loadOpencodeProjectSkills(params.ctx.directory), ]); @@ -59,11 +65,13 @@ export async function applyCommandConfig(params: { ...skillsToCommandDefinitionRecord(configSourceSkills), ...userCommands, ...userSkills, + ...globalAgentsSkills, ...opencodeGlobalCommands, ...opencodeGlobalSkills, ...systemCommands, ...projectCommands, ...projectSkills, + ...projectAgentsSkills, ...opencodeProjectCommands, ...opencodeProjectSkills, ...params.pluginComponents.commands, diff --git a/src/plugin/chat-params.test.ts b/src/plugin/chat-params.test.ts index c646c8283..5f17f36eb 100644 --- a/src/plugin/chat-params.test.ts +++ b/src/plugin/chat-params.test.ts @@ -1,6 +1,11 @@ -import { afterEach, describe, expect, test } from "bun:test" +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test" +import { mkdtempSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" -import { createChatParamsHandler } from "./chat-params" +import { createChatParamsHandler, type ChatParamsOutput } from "./chat-params" +import * as dataPathModule from "../shared/data-path" +import { writeProviderModelsCache } from "../shared" import { clearSessionPromptParams, getSessionPromptParams, @@ -8,8 +13,25 @@ import { } from "../shared/session-prompt-params-state" describe("createChatParamsHandler", () => { + let tempCacheRoot = "" + let getCacheDirSpy: ReturnType + + beforeEach(() => { + tempCacheRoot = mkdtempSync(join(tmpdir(), "chat-params-cache-")) + getCacheDirSpy = spyOn(dataPathModule, "getOmoOpenCodeCacheDir").mockReturnValue( + join(tempCacheRoot, "oh-my-opencode"), + ) + writeProviderModelsCache({ connected: [], models: {} }) + }) + afterEach(() => { clearSessionPromptParams("ses_chat_params") + clearSessionPromptParams("ses_chat_params_temperature") + writeProviderModelsCache({ connected: [], models: {} }) + getCacheDirSpy?.mockRestore() + if (tempCacheRoot) { + rmSync(tempCacheRoot, { recursive: true, force: true }) + } }) test("normalizes object-style agent payload and runs chat.params hooks", async () => { @@ -31,7 +53,7 @@ describe("createChatParamsHandler", () => { message: {}, } - const output = { + const output: ChatParamsOutput = { temperature: 0.1, topP: 1, topK: 1, @@ -63,7 +85,7 @@ describe("createChatParamsHandler", () => { message, } - const output = { + const output: ChatParamsOutput = { temperature: 0.1, topP: 1, topK: 1, @@ -79,7 +101,26 @@ describe("createChatParamsHandler", () => { test("applies stored prompt params for the session", async () => { //#given - setSessionPromptParams("ses_chat_params", { + writeProviderModelsCache({ + connected: ["openai"], + models: { + openai: [ + { + id: "gpt-5.4", + name: "GPT-5.4", + temperature: true, + reasoning: true, + variants: { + low: {}, + high: {}, + }, + limit: { output: 128_000 }, + }, + ], + }, + }) + + setSessionPromptParams("ses_chat_params_temperature", { temperature: 0.4, topP: 0.7, options: { @@ -94,14 +135,14 @@ describe("createChatParamsHandler", () => { }) const input = { - sessionID: "ses_chat_params", + sessionID: "ses_chat_params_temperature", agent: { name: "oracle" }, model: { providerID: "openai", modelID: "gpt-5.4" }, provider: { id: "openai" }, message: {}, } - const output = { + const output: ChatParamsOutput = { temperature: 0.1, topP: 1, topK: 1, @@ -123,7 +164,7 @@ describe("createChatParamsHandler", () => { maxTokens: 4096, }, }) - expect(getSessionPromptParams("ses_chat_params")).toEqual({ + expect(getSessionPromptParams("ses_chat_params_temperature")).toEqual({ temperature: 0.4, topP: 0.7, options: { @@ -133,4 +174,86 @@ describe("createChatParamsHandler", () => { }, }) }) + + test("drops gpt-5.4 temperature and clamps maxTokens from bundled model capabilities", async () => { + //#given + setSessionPromptParams("ses_chat_params_temperature", { + temperature: 0.7, + options: { + maxTokens: 200_000, + }, + }) + + const handler = createChatParamsHandler({ + anthropicEffort: null, + }) + + const input = { + sessionID: "ses_chat_params_temperature", + agent: { name: "oracle" }, + model: { providerID: "openai", modelID: "gpt-5.4" }, + provider: { id: "openai" }, + message: {}, + } + + const output: ChatParamsOutput = { + temperature: 0.1, + topP: 1, + topK: 1, + options: {}, + } + + //#when + await handler(input, output) + + //#then + expect(output).toEqual({ + topP: 1, + topK: 1, + options: { + maxTokens: 128_000, + }, + }) + }) + + test("drops unsupported reasoning settings from bundled model capabilities", async () => { + //#given + setSessionPromptParams("ses_chat_params", { + temperature: 0.4, + options: { + reasoningEffort: "high", + thinking: { type: "enabled", budgetTokens: 4096 }, + }, + }) + + const handler = createChatParamsHandler({ + anthropicEffort: null, + }) + + const input = { + sessionID: "ses_chat_params", + agent: { name: "oracle" }, + model: { providerID: "openai", modelID: "gpt-4.1" }, + provider: { id: "openai" }, + message: {}, + } + + const output = { + temperature: 0.1, + topP: 1, + topK: 1, + options: {}, + } + + //#when + await handler(input, output) + + //#then + expect(output).toEqual({ + temperature: 0.4, + topP: 1, + topK: 1, + options: {}, + }) + }) }) diff --git a/src/plugin/chat-params.ts b/src/plugin/chat-params.ts index d265b57d3..d69a14f8e 100644 --- a/src/plugin/chat-params.ts +++ b/src/plugin/chat-params.ts @@ -1,6 +1,6 @@ import { normalizeSDKResponse } from "../shared/normalize-sdk-response" import { getSessionPromptParams } from "../shared/session-prompt-params-state" -import { resolveCompatibleModelSettings } from "../shared" +import { getModelCapabilities, resolveCompatibleModelSettings } from "../shared" export type ChatParamsInput = { sessionID: string @@ -21,25 +21,6 @@ export type ChatParamsOutput = { options: Record } -type ProviderListClient = { - provider?: { - list?: () => Promise - } -} - -type ProviderModelMetadata = { - variants?: Record -} - -type ProviderListEntry = { - id?: string - models?: Record -} - -type ProviderListData = { - all?: ProviderListEntry[] -} - function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null } @@ -101,33 +82,9 @@ function isChatParamsOutput(raw: unknown): raw is ChatParamsOutput { return isRecord(raw.options) } -async function getVariantCapabilities( - client: ProviderListClient | undefined, - model: { providerID: string; modelID: string }, -): Promise { - const providerList = client?.provider?.list - if (typeof providerList !== "function") { - return undefined - } - - try { - const response = await providerList() - const data = normalizeSDKResponse(response, {}) - const providerEntry = data.all?.find((entry) => entry.id === model.providerID) - const variants = providerEntry?.models?.[model.modelID]?.variants - if (!variants) { - return undefined - } - - return Object.keys(variants) - } catch { - return undefined - } -} - export function createChatParamsHandler(args: { anthropicEffort: { "chat.params"?: (input: ChatParamsHookInput, output: ChatParamsOutput) => Promise } | null - client?: ProviderListClient + client?: unknown }): (input: unknown, output: unknown) => Promise { return async (input, output): Promise => { const normalizedInput = buildChatParamsInput(input) @@ -150,7 +107,10 @@ export function createChatParamsHandler(args: { } } - const variantCapabilities = await getVariantCapabilities(args.client, normalizedInput.model) + const capabilities = getModelCapabilities({ + providerID: normalizedInput.model.providerID, + modelID: normalizedInput.model.modelID, + }) const compatibility = resolveCompatibleModelSettings({ providerID: normalizedInput.model.providerID, @@ -162,10 +122,12 @@ export function createChatParamsHandler(args: { reasoningEffort: typeof output.options.reasoningEffort === "string" ? output.options.reasoningEffort : undefined, + temperature: typeof output.temperature === "number" ? output.temperature : undefined, + topP: typeof output.topP === "number" ? output.topP : undefined, + maxTokens: typeof output.options.maxTokens === "number" ? output.options.maxTokens : undefined, + thinking: isRecord(output.options.thinking) ? output.options.thinking : undefined, }, - capabilities: { - variants: variantCapabilities, - }, + capabilities, }) if (normalizedInput.rawMessage) { @@ -183,6 +145,38 @@ export function createChatParamsHandler(args: { delete output.options.reasoningEffort } + if ("temperature" in compatibility) { + if (compatibility.temperature !== undefined) { + output.temperature = compatibility.temperature + } else { + delete output.temperature + } + } + + if ("topP" in compatibility) { + if (compatibility.topP !== undefined) { + output.topP = compatibility.topP + } else { + delete output.topP + } + } + + if ("maxTokens" in compatibility) { + if (compatibility.maxTokens !== undefined) { + output.options.maxTokens = compatibility.maxTokens + } else { + delete output.options.maxTokens + } + } + + if ("thinking" in compatibility) { + if (compatibility.thinking !== undefined) { + output.options.thinking = compatibility.thinking + } else { + delete output.options.thinking + } + } + await args.anthropicEffort?.["chat.params"]?.(normalizedInput, output) } } diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index daa5e4ff5..60ea82415 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -184,6 +184,7 @@ export function createSessionHooks(args: { showStartupToast: isHookEnabled("startup-toast"), isSisyphusEnabled: pluginConfig.sisyphus_agent?.disabled !== true, autoUpdate: pluginConfig.auto_update ?? true, + modelCapabilities: pluginConfig.model_capabilities, })) : null diff --git a/src/plugin/ultrawork-db-model-override.test.ts b/src/plugin/ultrawork-db-model-override.test.ts index db364a97b..a5b350e75 100644 --- a/src/plugin/ultrawork-db-model-override.test.ts +++ b/src/plugin/ultrawork-db-model-override.test.ts @@ -22,6 +22,10 @@ function flushWithTimeout(): Promise { return new Promise((resolve) => setTimeout(resolve, 10)) } +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + describe("scheduleDeferredModelOverride", () => { let tempDir: string let dbPath: string @@ -60,9 +64,7 @@ describe("scheduleDeferredModelOverride", () => { const db = new Database(dbPath) db.run( `INSERT INTO message (id, session_id, data) VALUES (?, ?, ?)`, - id, - "ses_test", - JSON.stringify({ model }), + [id, "ses_test", JSON.stringify({ model })], ) db.close() } @@ -178,7 +180,7 @@ describe("scheduleDeferredModelOverride", () => { ) }) - test("should not crash when DB file exists but is corrupted", async () => { + test("should log a DB failure when DB file exists but is corrupted", async () => { //#given const { chmodSync, writeFileSync } = await import("node:fs") const corruptedDbPath = join(tempDir, "opencode", "opencode.db") @@ -194,9 +196,16 @@ describe("scheduleDeferredModelOverride", () => { await flushMicrotasks(5) //#then - expect(logSpy).toHaveBeenCalledWith( - expect.stringContaining("Failed to open DB"), - expect.objectContaining({ messageId: "msg_corrupt" }), + const failureCall = logSpy.mock.calls.find(([message, metadata]) => + typeof message === "string" + && ( + message.includes("Failed to open DB") + || message.includes("Deferred DB update failed with error") + ) + && isRecord(metadata) + && metadata.messageId === "msg_corrupt" ) + + expect(failureCall).toBeDefined() }) }) diff --git a/src/shared/agent-variant.test.ts b/src/shared/agent-variant.test.ts index 95f501c54..00ef030fb 100644 --- a/src/shared/agent-variant.test.ts +++ b/src/shared/agent-variant.test.ts @@ -113,9 +113,9 @@ describe("resolveVariantForModel", () => { }) test("returns correct variant for openai provider (hephaestus agent)", () => { - // #given hephaestus has openai/gpt-5.3-codex with variant "medium" in its chain + // #given hephaestus has openai/gpt-5.4 with variant "medium" in its chain const config = {} as OhMyOpenCodeConfig - const model = { providerID: "openai", modelID: "gpt-5.3-codex" } + const model = { providerID: "openai", modelID: "gpt-5.4" } // #when const variant = resolveVariantForModel(config, "hephaestus", model) diff --git a/src/shared/connected-providers-cache.test.ts b/src/shared/connected-providers-cache.test.ts index 183f9c712..73c905d25 100644 --- a/src/shared/connected-providers-cache.test.ts +++ b/src/shared/connected-providers-cache.test.ts @@ -7,6 +7,7 @@ import { tmpdir } from "node:os" import { join } from "node:path" import { createConnectedProvidersCacheStore, + findProviderModelMetadata, } from "./connected-providers-cache" let fakeUserCacheRoot = "" @@ -68,8 +69,14 @@ describe("updateConnectedProvidersCache", () => { expect(cache).not.toBeNull() expect(cache!.connected).toEqual(["openai", "anthropic"]) expect(cache!.models).toEqual({ - openai: ["gpt-5.3-codex", "gpt-5.4"], - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6"], + openai: [ + { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" }, + { id: "gpt-5.4", name: "GPT-5.4" }, + ], + anthropic: [ + { id: "claude-opus-4-6", name: "Claude Opus 4.6" }, + { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, + ], }) }) @@ -174,4 +181,86 @@ describe("updateConnectedProvidersCache", () => { } } }) + + test("findProviderModelMetadata returns rich cached metadata", async () => { + //#given + const mockClient = { + provider: { + list: async () => ({ + data: { + connected: ["openai"], + all: [ + { + id: "openai", + models: { + "gpt-5.4": { + id: "gpt-5.4", + name: "GPT-5.4", + temperature: false, + variants: { + low: {}, + high: {}, + }, + limit: { output: 128000 }, + }, + }, + }, + ], + }, + }), + }, + } + + await testCacheStore.updateConnectedProvidersCache(mockClient) + const cache = testCacheStore.readProviderModelsCache() + + //#when + const result = findProviderModelMetadata("openai", "gpt-5.4", cache) + + //#then + expect(result).toEqual({ + id: "gpt-5.4", + name: "GPT-5.4", + temperature: false, + variants: { + low: {}, + high: {}, + }, + limit: { output: 128000 }, + }) + }) + + test("keeps normalized fallback ids when raw metadata id is not a string", async () => { + const mockClient = { + provider: { + list: async () => ({ + data: { + connected: ["openai"], + all: [ + { + id: "openai", + models: { + "o3-mini": { + id: 123, + name: "o3-mini", + }, + }, + }, + ], + }, + }), + }, + } + + await testCacheStore.updateConnectedProvidersCache(mockClient) + const cache = testCacheStore.readProviderModelsCache() + + expect(cache?.models.openai).toEqual([ + { id: "o3-mini", name: "o3-mini" }, + ]) + expect(findProviderModelMetadata("openai", "o3-mini", cache)).toEqual({ + id: "o3-mini", + name: "o3-mini", + }) + }) }) diff --git a/src/shared/connected-providers-cache.ts b/src/shared/connected-providers-cache.ts index 692d35dd2..cf17852cd 100644 --- a/src/shared/connected-providers-cache.ts +++ b/src/shared/connected-providers-cache.ts @@ -11,20 +11,39 @@ interface ConnectedProvidersCache { updatedAt: string } -interface ModelMetadata { +export interface ModelMetadata { id: string provider?: string context?: number output?: number name?: string + variants?: Record + limit?: { + context?: number + input?: number + output?: number + } + modalities?: { + input?: string[] + output?: string[] + } + capabilities?: Record + reasoning?: boolean + temperature?: boolean + tool_call?: boolean + [key: string]: unknown } -interface ProviderModelsCache { +export interface ProviderModelsCache { models: Record connected: string[] updatedAt: string } +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + export function createConnectedProvidersCacheStore( getCacheDir: () => string = dataPath.getOmoOpenCodeCacheDir ) { @@ -119,7 +138,7 @@ export function createConnectedProvidersCacheStore( return existsSync(cacheFile) } - function writeProviderModelsCache(data: { models: Record; connected: string[] }): void { + function writeProviderModelsCache(data: { models: Record; connected: string[] }): void { ensureCacheDir() const cacheFile = getCacheFilePath(PROVIDER_MODELS_CACHE_FILE) @@ -164,14 +183,27 @@ export function createConnectedProvidersCacheStore( writeConnectedProvidersCache(connected) - const modelsByProvider: Record = {} + const modelsByProvider: Record = {} const allProviders = result.data?.all ?? [] for (const provider of allProviders) { if (provider.models) { - const modelIds = Object.keys(provider.models) - if (modelIds.length > 0) { - modelsByProvider[provider.id] = modelIds + const modelMetadata = Object.entries(provider.models).map(([modelID, rawMetadata]) => { + if (!isRecord(rawMetadata)) { + return { id: modelID } + } + + const normalizedID = typeof rawMetadata.id === "string" + ? rawMetadata.id + : modelID + + return { + ...rawMetadata, + id: normalizedID, + } satisfies ModelMetadata + }) + if (modelMetadata.length > 0) { + modelsByProvider[provider.id] = modelMetadata } } } @@ -200,6 +232,32 @@ export function createConnectedProvidersCacheStore( } } +export function findProviderModelMetadata( + providerID: string, + modelID: string, + cache: ProviderModelsCache | null = defaultConnectedProvidersCacheStore.readProviderModelsCache(), +): ModelMetadata | undefined { + const providerModels = cache?.models?.[providerID] + if (!providerModels) { + return undefined + } + + for (const entry of providerModels) { + if (typeof entry === "string") { + if (entry === modelID) { + return { id: entry } + } + continue + } + + if (entry?.id === modelID) { + return entry + } + } + + return undefined +} + const defaultConnectedProvidersCacheStore = createConnectedProvidersCacheStore( () => dataPath.getOmoOpenCodeCacheDir() ) diff --git a/src/shared/context-limit-resolver.test.ts b/src/shared/context-limit-resolver.test.ts index 5ce62a8df..749eef287 100644 --- a/src/shared/context-limit-resolver.test.ts +++ b/src/shared/context-limit-resolver.test.ts @@ -28,12 +28,29 @@ describe("resolveActualContextLimit", () => { resetContextLimitEnv() }) - it("returns the default Anthropic limit when 1M mode is disabled despite a cached limit", () => { + it("returns cached limit for Anthropic 4.6 models when 1M mode is disabled (GA support)", () => { // given delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] delete process.env[VERTEX_CONTEXT_ENV_KEY] const modelContextLimitsCache = new Map() - modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 123456) + modelContextLimitsCache.set("anthropic/claude-opus-4-6", 1_000_000) + + // when + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-6", { + anthropicContext1MEnabled: false, + modelContextLimitsCache, + }) + + // then — models.dev reports 1M for GA models, resolver should respect it + expect(actualLimit).toBe(1_000_000) + }) + + it("returns default 200K for older Anthropic models even when cached limit is higher", () => { + // given + delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] + delete process.env[VERTEX_CONTEXT_ENV_KEY] + const modelContextLimitsCache = new Map() + modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 500_000) // when const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", { @@ -42,7 +59,38 @@ describe("resolveActualContextLimit", () => { }) // then - expect(actualLimit).toBe(200000) + expect(actualLimit).toBe(200_000) + }) + + it("returns default 200K for Anthropic models without cached limit and 1M mode disabled", () => { + // given + delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] + delete process.env[VERTEX_CONTEXT_ENV_KEY] + + // when + const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", { + anthropicContext1MEnabled: false, + }) + + // then + expect(actualLimit).toBe(200_000) + }) + + it("explicit 1M mode takes priority over cached limit", () => { + // given + delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] + delete process.env[VERTEX_CONTEXT_ENV_KEY] + const modelContextLimitsCache = new Map() + modelContextLimitsCache.set("anthropic/claude-sonnet-4-5", 200_000) + + // when + const actualLimit = resolveActualContextLimit("anthropic", "claude-sonnet-4-5", { + anthropicContext1MEnabled: true, + modelContextLimitsCache, + }) + + // then — explicit 1M flag overrides cached 200K + expect(actualLimit).toBe(1_000_000) }) it("treats Anthropics aliases as Anthropic providers", () => { @@ -61,6 +109,23 @@ describe("resolveActualContextLimit", () => { expect(actualLimit).toBe(200000) }) + it("supports Anthropic 4.6 dot-version model IDs without explicit 1M mode", () => { + // given + delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] + delete process.env[VERTEX_CONTEXT_ENV_KEY] + const modelContextLimitsCache = new Map() + modelContextLimitsCache.set("anthropic/claude-opus-4.6", 1_000_000) + + // when + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.6", { + anthropicContext1MEnabled: false, + modelContextLimitsCache, + }) + + // then + expect(actualLimit).toBe(1_000_000) + }) + it("returns null for non-Anthropic providers without a cached limit", () => { // given delete process.env[ANTHROPIC_CONTEXT_ENV_KEY] diff --git a/src/shared/context-limit-resolver.ts b/src/shared/context-limit-resolver.ts index 361fa45d0..bc19a4191 100644 --- a/src/shared/context-limit-resolver.ts +++ b/src/shared/context-limit-resolver.ts @@ -1,6 +1,12 @@ import process from "node:process" const DEFAULT_ANTHROPIC_ACTUAL_LIMIT = 200_000 +const ANTHROPIC_NO_HEADER_GA_MODEL_IDS = new Set([ + "claude-opus-4-6", + "claude-opus-4.6", + "claude-sonnet-4-6", + "claude-sonnet-4.6", +]) export type ContextLimitModelCacheState = { anthropicContext1MEnabled: boolean @@ -20,13 +26,23 @@ function getAnthropicActualLimit(modelCacheState?: ContextLimitModelCacheState): : DEFAULT_ANTHROPIC_ACTUAL_LIMIT } +function isAnthropicNoHeaderGaModel(modelID: string): boolean { + return ANTHROPIC_NO_HEADER_GA_MODEL_IDS.has(modelID.toLowerCase()) +} + export function resolveActualContextLimit( providerID: string, modelID: string, modelCacheState?: ContextLimitModelCacheState, ): number | null { if (isAnthropicProvider(providerID)) { - return getAnthropicActualLimit(modelCacheState) + const explicit1M = getAnthropicActualLimit(modelCacheState) + if (explicit1M === 1_000_000) return explicit1M + + const cachedLimit = modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`) + if (cachedLimit && isAnthropicNoHeaderGaModel(modelID)) return cachedLimit + + return DEFAULT_ANTHROPIC_ACTUAL_LIMIT } return modelCacheState?.modelContextLimitsCache?.get(`${providerID}/${modelID}`) ?? null diff --git a/src/shared/index.ts b/src/shared/index.ts index 9f296d797..e178952b5 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -43,6 +43,9 @@ export type { ModelResolutionResult, } from "./model-resolution-types" export * from "./model-availability" +export * from "./model-capabilities" +export * from "./model-capabilities-cache" +export * from "./model-capability-heuristics" export * from "./model-settings-compatibility" export * from "./fallback-model-availability" export * from "./connected-providers-cache" @@ -59,6 +62,7 @@ export * from "./truncate-description" export * from "./opencode-storage-paths" export * from "./opencode-message-dir" export * from "./opencode-command-dirs" +export * from "./project-discovery-dirs" export * from "./normalize-sdk-response" export * from "./session-directory-resolver" export * from "./prompt-tools" @@ -66,3 +70,4 @@ export * from "./internal-initiator-marker" export * from "./plugin-command-discovery" export { SessionCategoryRegistry } from "./session-category-registry" export * from "./plugin-identity" +export * from "./log-legacy-plugin-startup-warning" diff --git a/src/shared/legacy-plugin-warning.test.ts b/src/shared/legacy-plugin-warning.test.ts new file mode 100644 index 000000000..3bc16c3b1 --- /dev/null +++ b/src/shared/legacy-plugin-warning.test.ts @@ -0,0 +1,81 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { checkForLegacyPluginEntry } from "./legacy-plugin-warning" + +describe("checkForLegacyPluginEntry", () => { + let testConfigDir = "" + + beforeEach(() => { + testConfigDir = join(tmpdir(), `omo-legacy-check-${Date.now()}-${Math.random().toString(36).slice(2)}`) + mkdirSync(testConfigDir, { recursive: true }) + }) + + afterEach(() => { + rmSync(testConfigDir, { recursive: true, force: true }) + }) + + it("detects a bare legacy plugin entry", () => { + // given + writeFileSync(join(testConfigDir, "opencode.json"), JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2)) + + // when + const result = checkForLegacyPluginEntry(testConfigDir) + + // then + expect(result.hasLegacyEntry).toBe(true) + expect(result.hasCanonicalEntry).toBe(false) + expect(result.legacyEntries).toEqual(["oh-my-opencode"]) + }) + + it("detects a version-pinned legacy plugin entry", () => { + // given + writeFileSync(join(testConfigDir, "opencode.json"), JSON.stringify({ plugin: ["oh-my-opencode@3.10.0"] }, null, 2)) + + // when + const result = checkForLegacyPluginEntry(testConfigDir) + + // then + expect(result.hasLegacyEntry).toBe(true) + expect(result.hasCanonicalEntry).toBe(false) + expect(result.legacyEntries).toEqual(["oh-my-opencode@3.10.0"]) + }) + + it("does not flag a canonical plugin entry", () => { + // given + writeFileSync(join(testConfigDir, "opencode.json"), JSON.stringify({ plugin: ["oh-my-openagent"] }, null, 2)) + + // when + const result = checkForLegacyPluginEntry(testConfigDir) + + // then + expect(result.hasLegacyEntry).toBe(false) + expect(result.hasCanonicalEntry).toBe(true) + expect(result.legacyEntries).toEqual([]) + }) + + it("detects legacy entries in quoted jsonc config", () => { + // given + writeFileSync(join(testConfigDir, "opencode.jsonc"), '{\n "plugin": ["oh-my-opencode"]\n}\n') + + // when + const result = checkForLegacyPluginEntry(testConfigDir) + + // then + expect(result.hasLegacyEntry).toBe(true) + expect(result.legacyEntries).toEqual(["oh-my-opencode"]) + }) + + it("returns no warning data when config is missing", () => { + // given — empty dir, no config files + + // when + const result = checkForLegacyPluginEntry(testConfigDir) + + // then + expect(result.hasLegacyEntry).toBe(false) + expect(result.hasCanonicalEntry).toBe(false) + expect(result.legacyEntries).toEqual([]) + }) +}) diff --git a/src/shared/legacy-plugin-warning.ts b/src/shared/legacy-plugin-warning.ts new file mode 100644 index 000000000..c8a7e94df --- /dev/null +++ b/src/shared/legacy-plugin-warning.ts @@ -0,0 +1,66 @@ +import { existsSync, readFileSync } from "node:fs" +import { join } from "node:path" + +import { parseJsoncSafe } from "./jsonc-parser" +import { getOpenCodeConfigPaths } from "./opencode-config-dir" +import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "./plugin-identity" + +interface OpenCodeConfig { + plugin?: string[] +} + +export interface LegacyPluginCheckResult { + hasLegacyEntry: boolean + hasCanonicalEntry: boolean + legacyEntries: string[] +} + +function getOpenCodeConfigPath(overrideConfigDir?: string): string | null { + if (overrideConfigDir) { + const jsonPath = join(overrideConfigDir, "opencode.json") + const jsoncPath = join(overrideConfigDir, "opencode.jsonc") + if (existsSync(jsoncPath)) return jsoncPath + if (existsSync(jsonPath)) return jsonPath + return null + } + + const { configJsonc, configJson } = getOpenCodeConfigPaths({ binary: "opencode", version: null }) + + if (existsSync(configJsonc)) return configJsonc + if (existsSync(configJson)) return configJson + return null +} + +function isLegacyPluginEntry(entry: string): boolean { + return entry === LEGACY_PLUGIN_NAME || entry.startsWith(`${LEGACY_PLUGIN_NAME}@`) +} + +function isCanonicalPluginEntry(entry: string): boolean { + return entry === PLUGIN_NAME || entry.startsWith(`${PLUGIN_NAME}@`) +} + +export function checkForLegacyPluginEntry(overrideConfigDir?: string): LegacyPluginCheckResult { + const configPath = getOpenCodeConfigPath(overrideConfigDir) + if (!configPath) { + return { hasLegacyEntry: false, hasCanonicalEntry: false, legacyEntries: [] } + } + + try { + const content = readFileSync(configPath, "utf-8") + const parseResult = parseJsoncSafe(content) + if (!parseResult.data) { + return { hasLegacyEntry: false, hasCanonicalEntry: false, legacyEntries: [] } + } + + const legacyEntries = (parseResult.data.plugin ?? []).filter(isLegacyPluginEntry) + const hasCanonicalEntry = (parseResult.data.plugin ?? []).some(isCanonicalPluginEntry) + + return { + hasLegacyEntry: legacyEntries.length > 0, + hasCanonicalEntry, + legacyEntries, + } + } catch { + return { hasLegacyEntry: false, hasCanonicalEntry: false, legacyEntries: [] } + } +} diff --git a/src/shared/log-legacy-plugin-startup-warning.test.ts b/src/shared/log-legacy-plugin-startup-warning.test.ts new file mode 100644 index 000000000..5259515b8 --- /dev/null +++ b/src/shared/log-legacy-plugin-startup-warning.test.ts @@ -0,0 +1,80 @@ +import { afterAll, beforeEach, describe, expect, it, mock } from "bun:test" +import type { LegacyPluginCheckResult } from "./legacy-plugin-warning" + +function createLegacyPluginCheckResult( + overrides: Partial = {}, +): LegacyPluginCheckResult { + return { + hasLegacyEntry: false, + hasCanonicalEntry: false, + legacyEntries: [], + ...overrides, + } +} + +const mockCheckForLegacyPluginEntry = mock(() => createLegacyPluginCheckResult()) + +const mockLog = mock(() => {}) + +mock.module("./legacy-plugin-warning", () => ({ + checkForLegacyPluginEntry: mockCheckForLegacyPluginEntry, +})) + +mock.module("./logger", () => ({ + log: mockLog, +})) + +afterAll(() => { + mock.restore() +}) + +async function importFreshStartupWarningModule(): Promise { + return import(`./log-legacy-plugin-startup-warning?test=${Date.now()}-${Math.random()}`) +} + +describe("logLegacyPluginStartupWarning", () => { + beforeEach(() => { + mockCheckForLegacyPluginEntry.mockReset() + mockLog.mockReset() + + mockCheckForLegacyPluginEntry.mockReturnValue(createLegacyPluginCheckResult()) + }) + + describe("#given OpenCode config contains legacy plugin entries", () => { + it("logs the legacy entries with canonical replacements", async () => { + //#given + mockCheckForLegacyPluginEntry.mockReturnValue(createLegacyPluginCheckResult({ + hasLegacyEntry: true, + legacyEntries: ["oh-my-opencode", "oh-my-opencode@3.13.1"], + })) + const { logLegacyPluginStartupWarning } = await importFreshStartupWarningModule() + + //#when + logLegacyPluginStartupWarning() + + //#then + expect(mockLog).toHaveBeenCalledTimes(1) + expect(mockLog).toHaveBeenCalledWith( + "[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", + { + legacyEntries: ["oh-my-opencode", "oh-my-opencode@3.13.1"], + suggestedEntries: ["oh-my-openagent", "oh-my-openagent@3.13.1"], + hasCanonicalEntry: false, + }, + ) + }) + }) + + describe("#given OpenCode config uses only canonical plugin entries", () => { + it("does not log a startup warning", async () => { + //#given + const { logLegacyPluginStartupWarning } = await importFreshStartupWarningModule() + + //#when + logLegacyPluginStartupWarning() + + //#then + expect(mockLog).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/shared/log-legacy-plugin-startup-warning.ts b/src/shared/log-legacy-plugin-startup-warning.ts new file mode 100644 index 000000000..f5712a2e9 --- /dev/null +++ b/src/shared/log-legacy-plugin-startup-warning.ts @@ -0,0 +1,28 @@ +import { checkForLegacyPluginEntry } from "./legacy-plugin-warning" +import { log } from "./logger" +import { LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "./plugin-identity" + +function toCanonicalEntry(entry: string): string { + if (entry === LEGACY_PLUGIN_NAME) { + return PLUGIN_NAME + } + + if (entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) { + return `${PLUGIN_NAME}${entry.slice(LEGACY_PLUGIN_NAME.length)}` + } + + return entry +} + +export function logLegacyPluginStartupWarning(): void { + const result = checkForLegacyPluginEntry() + if (!result.hasLegacyEntry) { + return + } + + log("[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", { + legacyEntries: result.legacyEntries, + suggestedEntries: result.legacyEntries.map(toCanonicalEntry), + hasCanonicalEntry: result.hasCanonicalEntry, + }) +} diff --git a/src/shared/model-capabilities-cache.test.ts b/src/shared/model-capabilities-cache.test.ts new file mode 100644 index 000000000..0773a5fe0 --- /dev/null +++ b/src/shared/model-capabilities-cache.test.ts @@ -0,0 +1,165 @@ +/// + +import { afterEach, beforeEach, describe, expect, test } from "bun:test" + +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { + buildModelCapabilitiesSnapshotFromModelsDev, + createModelCapabilitiesCacheStore, + MODELS_DEV_SOURCE_URL, +} from "./model-capabilities-cache" + +let fakeUserCacheRoot = "" +let testCacheDir = "" + +describe("model-capabilities-cache", () => { + beforeEach(() => { + fakeUserCacheRoot = mkdtempSync(join(tmpdir(), "model-capabilities-cache-")) + testCacheDir = join(fakeUserCacheRoot, "oh-my-opencode") + }) + + afterEach(() => { + if (existsSync(fakeUserCacheRoot)) { + rmSync(fakeUserCacheRoot, { recursive: true, force: true }) + } + fakeUserCacheRoot = "" + testCacheDir = "" + }) + + test("builds a normalized snapshot from provider-keyed models.dev data", () => { + //#given + const raw = { + openai: { + models: { + "gpt-5.4": { + id: "gpt-5.4", + family: "gpt", + reasoning: true, + temperature: false, + tool_call: true, + modalities: { + input: ["text", "image"], + output: ["text"], + }, + limit: { + context: 1_050_000, + output: 128_000, + }, + }, + }, + }, + anthropic: { + models: { + "claude-sonnet-4-6": { + family: "claude-sonnet", + reasoning: true, + temperature: true, + limit: { + context: 1_000_000, + output: 64_000, + }, + }, + }, + }, + } + + //#when + const snapshot = buildModelCapabilitiesSnapshotFromModelsDev(raw) + + //#then + expect(snapshot.sourceUrl).toBe(MODELS_DEV_SOURCE_URL) + expect(snapshot.models["gpt-5.4"]).toEqual({ + id: "gpt-5.4", + family: "gpt", + reasoning: true, + temperature: false, + toolCall: true, + modalities: { + input: ["text", "image"], + output: ["text"], + }, + limit: { + context: 1_050_000, + output: 128_000, + }, + }) + expect(snapshot.models["claude-sonnet-4-6"]).toEqual({ + id: "claude-sonnet-4-6", + family: "claude-sonnet", + reasoning: true, + temperature: true, + limit: { + context: 1_000_000, + output: 64_000, + }, + }) + }) + + test("merges repeated snapshot entries without materializing empty optional objects", () => { + const raw = { + openai: { + models: { + "gpt-5.4": { + id: "gpt-5.4", + family: "gpt", + }, + }, + }, + alias: { + models: { + "gpt-5.4-preview": { + id: "gpt-5.4", + reasoning: true, + }, + }, + }, + } + + const snapshot = buildModelCapabilitiesSnapshotFromModelsDev(raw) + + expect(snapshot.models["gpt-5.4"]).toEqual({ + id: "gpt-5.4", + family: "gpt", + reasoning: true, + }) + expect(snapshot.models["gpt-5.4"]).not.toHaveProperty("modalities") + expect(snapshot.models["gpt-5.4"]).not.toHaveProperty("limit") + }) + + test("refresh writes cache and preserves unrelated files in the cache directory", async () => { + //#given + const sentinelPath = join(testCacheDir, "keep-me.json") + const store = createModelCapabilitiesCacheStore(() => testCacheDir) + mkdirSync(testCacheDir, { recursive: true }) + writeFileSync(sentinelPath, JSON.stringify({ keep: true })) + + const fetchImpl: typeof fetch = async () => + new Response(JSON.stringify({ + openai: { + models: { + "gpt-5.4": { + id: "gpt-5.4", + family: "gpt", + reasoning: true, + limit: { output: 128_000 }, + }, + }, + }, + }), { + status: 200, + headers: { "content-type": "application/json" }, + }) + + //#when + const snapshot = await store.refreshModelCapabilitiesCache({ fetchImpl }) + const reloadedStore = createModelCapabilitiesCacheStore(() => testCacheDir) + + //#then + expect(snapshot.models["gpt-5.4"]?.limit?.output).toBe(128_000) + expect(existsSync(sentinelPath)).toBe(true) + expect(readFileSync(sentinelPath, "utf-8")).toBe(JSON.stringify({ keep: true })) + expect(reloadedStore.readModelCapabilitiesCache()).toEqual(snapshot) + }) +}) diff --git a/src/shared/model-capabilities-cache.ts b/src/shared/model-capabilities-cache.ts new file mode 100644 index 000000000..bff841c68 --- /dev/null +++ b/src/shared/model-capabilities-cache.ts @@ -0,0 +1,248 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs" +import { join } from "path" +import * as dataPath from "./data-path" +import { log } from "./logger" +import type { ModelCapabilitiesSnapshot, ModelCapabilitiesSnapshotEntry } from "./model-capabilities" + +export const MODELS_DEV_SOURCE_URL = "https://models.dev/api.json" +const MODEL_CAPABILITIES_CACHE_FILE = "model-capabilities.json" + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} + +function readBoolean(value: unknown): boolean | undefined { + return typeof value === "boolean" ? value : undefined +} + +function readNumber(value: unknown): number | undefined { + return typeof value === "number" ? value : undefined +} + +function readString(value: unknown): string | undefined { + return typeof value === "string" ? value : undefined +} + +function readStringArray(value: unknown): string[] | undefined { + if (!Array.isArray(value)) { + return undefined + } + + const result = value.filter((item): item is string => typeof item === "string") + return result.length > 0 ? result : undefined +} + +function normalizeSnapshotEntry(rawModelID: string, rawModel: unknown): ModelCapabilitiesSnapshotEntry | undefined { + if (!isRecord(rawModel)) { + return undefined + } + + const id = readString(rawModel.id) ?? rawModelID + const family = readString(rawModel.family) + const reasoning = readBoolean(rawModel.reasoning) + const temperature = readBoolean(rawModel.temperature) + const toolCall = readBoolean(rawModel.tool_call) + + const rawModalities = isRecord(rawModel.modalities) ? rawModel.modalities : undefined + const modalitiesInput = readStringArray(rawModalities?.input) + const modalitiesOutput = readStringArray(rawModalities?.output) + const modalities = modalitiesInput || modalitiesOutput + ? { + ...(modalitiesInput ? { input: modalitiesInput } : {}), + ...(modalitiesOutput ? { output: modalitiesOutput } : {}), + } + : undefined + + const rawLimit = isRecord(rawModel.limit) ? rawModel.limit : undefined + const limitContext = readNumber(rawLimit?.context) + const limitInput = readNumber(rawLimit?.input) + const limitOutput = readNumber(rawLimit?.output) + const limit = limitContext !== undefined || limitInput !== undefined || limitOutput !== undefined + ? { + ...(limitContext !== undefined ? { context: limitContext } : {}), + ...(limitInput !== undefined ? { input: limitInput } : {}), + ...(limitOutput !== undefined ? { output: limitOutput } : {}), + } + : undefined + + return { + id, + ...(family ? { family } : {}), + ...(reasoning !== undefined ? { reasoning } : {}), + ...(temperature !== undefined ? { temperature } : {}), + ...(toolCall !== undefined ? { toolCall } : {}), + ...(modalities ? { modalities } : {}), + ...(limit ? { limit } : {}), + } +} + +function mergeSnapshotEntries( + existing: ModelCapabilitiesSnapshotEntry | undefined, + incoming: ModelCapabilitiesSnapshotEntry, +): ModelCapabilitiesSnapshotEntry { + if (!existing) { + return incoming + } + + const mergedModalities = existing.modalities || incoming.modalities + ? { + ...existing.modalities, + ...incoming.modalities, + } + : undefined + const mergedLimit = existing.limit || incoming.limit + ? { + ...existing.limit, + ...incoming.limit, + } + : undefined + + return { + ...existing, + ...incoming, + ...(mergedModalities ? { modalities: mergedModalities } : {}), + ...(mergedLimit ? { limit: mergedLimit } : {}), + } +} + +export function buildModelCapabilitiesSnapshotFromModelsDev(raw: unknown): ModelCapabilitiesSnapshot { + const models: Record = {} + const providers = isRecord(raw) ? raw : {} + + for (const providerValue of Object.values(providers)) { + if (!isRecord(providerValue)) { + continue + } + + const providerModels = providerValue.models + if (!isRecord(providerModels)) { + continue + } + + for (const [rawModelID, rawModel] of Object.entries(providerModels)) { + const normalizedEntry = normalizeSnapshotEntry(rawModelID, rawModel) + if (!normalizedEntry) { + continue + } + + models[normalizedEntry.id.toLowerCase()] = mergeSnapshotEntries( + models[normalizedEntry.id.toLowerCase()], + normalizedEntry, + ) + } + } + + return { + generatedAt: new Date().toISOString(), + sourceUrl: MODELS_DEV_SOURCE_URL, + models, + } +} + +export async function fetchModelCapabilitiesSnapshot(args: { + sourceUrl?: string + fetchImpl?: typeof fetch +} = {}): Promise { + const sourceUrl = args.sourceUrl ?? MODELS_DEV_SOURCE_URL + const fetchImpl = args.fetchImpl ?? fetch + const response = await fetchImpl(sourceUrl) + + if (!response.ok) { + throw new Error(`models.dev fetch failed with ${response.status}`) + } + + const raw = await response.json() + const snapshot = buildModelCapabilitiesSnapshotFromModelsDev(raw) + return { + ...snapshot, + sourceUrl, + } +} + +export function createModelCapabilitiesCacheStore( + getCacheDir: () => string = dataPath.getOmoOpenCodeCacheDir, +) { + let memSnapshot: ModelCapabilitiesSnapshot | null | undefined + + function getCacheFilePath(): string { + return join(getCacheDir(), MODEL_CAPABILITIES_CACHE_FILE) + } + + function ensureCacheDir(): void { + const cacheDir = getCacheDir() + if (!existsSync(cacheDir)) { + mkdirSync(cacheDir, { recursive: true }) + } + } + + function readModelCapabilitiesCache(): ModelCapabilitiesSnapshot | null { + if (memSnapshot !== undefined) { + return memSnapshot + } + + const cacheFile = getCacheFilePath() + if (!existsSync(cacheFile)) { + memSnapshot = null + log("[model-capabilities-cache] Cache file not found", { cacheFile }) + return null + } + + try { + const content = readFileSync(cacheFile, "utf-8") + const snapshot = JSON.parse(content) as ModelCapabilitiesSnapshot + memSnapshot = snapshot + log("[model-capabilities-cache] Read cache", { + modelCount: Object.keys(snapshot.models).length, + generatedAt: snapshot.generatedAt, + }) + return snapshot + } catch (error) { + memSnapshot = null + log("[model-capabilities-cache] Error reading cache", { error: String(error) }) + return null + } + } + + function hasModelCapabilitiesCache(): boolean { + return existsSync(getCacheFilePath()) + } + + function writeModelCapabilitiesCache(snapshot: ModelCapabilitiesSnapshot): void { + ensureCacheDir() + const cacheFile = getCacheFilePath() + + writeFileSync(cacheFile, JSON.stringify(snapshot, null, 2) + "\n") + memSnapshot = snapshot + log("[model-capabilities-cache] Cache written", { + modelCount: Object.keys(snapshot.models).length, + generatedAt: snapshot.generatedAt, + }) + } + + async function refreshModelCapabilitiesCache(args: { + sourceUrl?: string + fetchImpl?: typeof fetch + } = {}): Promise { + const snapshot = await fetchModelCapabilitiesSnapshot(args) + writeModelCapabilitiesCache(snapshot) + return snapshot + } + + return { + readModelCapabilitiesCache, + hasModelCapabilitiesCache, + writeModelCapabilitiesCache, + refreshModelCapabilitiesCache, + } +} + +const defaultModelCapabilitiesCacheStore = createModelCapabilitiesCacheStore( + () => dataPath.getOmoOpenCodeCacheDir(), +) + +export const { + readModelCapabilitiesCache, + hasModelCapabilitiesCache, + writeModelCapabilitiesCache, + refreshModelCapabilitiesCache, +} = defaultModelCapabilitiesCacheStore diff --git a/src/shared/model-capabilities.test.ts b/src/shared/model-capabilities.test.ts new file mode 100644 index 000000000..80747e333 --- /dev/null +++ b/src/shared/model-capabilities.test.ts @@ -0,0 +1,324 @@ +import { afterAll, describe, expect, test, mock } from "bun:test" + +// Mock connected-providers-cache to prevent local disk cache from polluting test results. +// Without this, findProviderModelMetadata reads real cached model metadata (e.g., from opencode serve) +// which causes the "prefers runtime models.dev cache" test to get different values than expected. +mock.module("./connected-providers-cache", () => ({ + findProviderModelMetadata: () => undefined, + readConnectedProvidersCache: () => null, + hasConnectedProvidersCache: () => false, + hasProviderModelsCache: () => false, +})) + +afterAll(() => { + mock.restore() +}) + +import { + getModelCapabilities, + getBundledModelCapabilitiesSnapshot, + type ModelCapabilitiesSnapshot, +} from "./model-capabilities" +import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements" + +describe("getModelCapabilities", () => { + const bundledSnapshot: ModelCapabilitiesSnapshot = { + generatedAt: "2026-03-25T00:00:00.000Z", + sourceUrl: "https://models.dev/api.json", + models: { + "claude-opus-4-6": { + id: "claude-opus-4-6", + family: "claude-opus", + reasoning: true, + temperature: true, + modalities: { + input: ["text", "image", "pdf"], + output: ["text"], + }, + limit: { + context: 1_000_000, + output: 128_000, + }, + toolCall: true, + }, + "gemini-3.1-pro": { + id: "gemini-3.1-pro", + family: "gemini", + reasoning: true, + temperature: true, + modalities: { + input: ["text", "image"], + output: ["text"], + }, + limit: { + context: 1_000_000, + output: 65_000, + }, + }, + "gpt-5.4": { + id: "gpt-5.4", + family: "gpt", + reasoning: true, + temperature: false, + modalities: { + input: ["text", "image", "pdf"], + output: ["text"], + }, + limit: { + context: 1_050_000, + output: 128_000, + }, + }, + }, + } + + test("uses runtime metadata before snapshot data", () => { + const result = getModelCapabilities({ + providerID: "anthropic", + modelID: "claude-opus-4-6", + runtimeModel: { + variants: { + low: {}, + medium: {}, + high: {}, + }, + }, + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "claude-opus-4-6", + family: "claude-opus", + variants: ["low", "medium", "high"], + supportsThinking: true, + supportsTemperature: true, + maxOutputTokens: 128_000, + toolCall: true, + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "snapshot-backed", + canonicalization: { source: "canonical" }, + snapshot: { source: "bundled-snapshot" }, + variants: { source: "runtime" }, + }) + }) + + test("reads structured runtime capabilities from the SDK v2 shape", () => { + const result = getModelCapabilities({ + providerID: "openai", + modelID: "gpt-5.4", + runtimeModel: { + capabilities: { + reasoning: true, + temperature: false, + toolcall: true, + input: { + text: true, + image: true, + }, + output: { + text: true, + }, + }, + }, + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "gpt-5.4", + reasoning: true, + supportsThinking: true, + supportsTemperature: false, + toolCall: true, + modalities: { + input: ["text", "image"], + output: ["text"], + }, + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "snapshot-backed", + reasoning: { source: "runtime" }, + supportsThinking: { source: "runtime" }, + toolCall: { source: "runtime" }, + }) + }) + + test("respects root-level thinking flags when providers do not nest them under capabilities", () => { + const result = getModelCapabilities({ + providerID: "custom-proxy", + modelID: "gpt-5.4", + runtimeModel: { + supportsThinking: true, + }, + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "gpt-5.4", + supportsThinking: true, + }) + expect(result.diagnostics).toMatchObject({ + supportsThinking: { source: "runtime" }, + }) + }) + + test("accepts runtime variant arrays without corrupting them into numeric keys", () => { + const result = getModelCapabilities({ + providerID: "openai", + modelID: "gpt-5.4", + runtimeModel: { + variants: ["low", "medium", "high", "xhigh"], + }, + bundledSnapshot, + }) + + expect(result.variants).toEqual(["low", "medium", "high", "xhigh"]) + }) + + test("normalizes the legacy Claude Opus thinking alias before snapshot lookup", () => { + const result = getModelCapabilities({ + providerID: "anthropic", + modelID: "claude-opus-4-6-thinking", + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "claude-opus-4-6", + family: "claude-opus", + supportsThinking: true, + supportsTemperature: true, + maxOutputTokens: 128_000, + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "alias-backed", + canonicalization: { + source: "exact-alias", + ruleID: "claude-opus-4-6-thinking-legacy-alias", + }, + snapshot: { source: "bundled-snapshot" }, + }) + }) + + test("maps local gemini aliases to canonical models.dev entries", () => { + const result = getModelCapabilities({ + providerID: "google", + modelID: "gemini-3.1-pro-high", + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "gemini-3.1-pro", + family: "gemini", + supportsThinking: true, + supportsTemperature: true, + maxOutputTokens: 65_000, + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "alias-backed", + canonicalization: { + source: "exact-alias", + ruleID: "gemini-3.1-pro-tier-alias", + }, + snapshot: { source: "bundled-snapshot" }, + }) + }) + + test("prefers runtime models.dev cache over bundled snapshot", () => { + const runtimeSnapshot: ModelCapabilitiesSnapshot = { + ...bundledSnapshot, + models: { + ...bundledSnapshot.models, + "gpt-5.4": { + ...bundledSnapshot.models["gpt-5.4"], + limit: { + context: 1_050_000, + output: 64_000, + }, + }, + }, + } + + const result = getModelCapabilities({ + providerID: "openai", + modelID: "gpt-5.4", + bundledSnapshot, + runtimeSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "gpt-5.4", + maxOutputTokens: 64_000, + supportsTemperature: false, + }) + expect(result.diagnostics).toMatchObject({ + snapshot: { source: "runtime-snapshot" }, + maxOutputTokens: { source: "runtime-snapshot" }, + supportsTemperature: { source: "runtime-snapshot" }, + }) + }) + + test("falls back to heuristic family rules when no snapshot entry exists", () => { + const result = getModelCapabilities({ + providerID: "openai", + modelID: "o3-mini", + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "o3-mini", + family: "openai-reasoning", + variants: ["low", "medium", "high"], + reasoningEfforts: ["none", "minimal", "low", "medium", "high"], + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "heuristic-backed", + snapshot: { source: "none" }, + family: { source: "heuristic" }, + reasoningEfforts: { source: "heuristic" }, + }) + }) + + test("detects prefixed o-series model IDs through the heuristic fallback", () => { + const result = getModelCapabilities({ + providerID: "azure-openai", + modelID: "openai/o3-mini", + bundledSnapshot, + }) + + expect(result).toMatchObject({ + canonicalModelID: "openai/o3-mini", + family: "openai-reasoning", + variants: ["low", "medium", "high"], + reasoningEfforts: ["none", "minimal", "low", "medium", "high"], + }) + expect(result.diagnostics).toMatchObject({ + resolutionMode: "heuristic-backed", + snapshot: { source: "none" }, + family: { source: "heuristic" }, + }) + }) + + test("keeps every built-in OmO requirement model snapshot-backed", () => { + const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const requirementModels = new Set() + + for (const requirement of Object.values(AGENT_MODEL_REQUIREMENTS)) { + for (const entry of requirement.fallbackChain) requirementModels.add(entry.model) + } + + for (const requirement of Object.values(CATEGORY_MODEL_REQUIREMENTS)) { + for (const entry of requirement.fallbackChain) requirementModels.add(entry.model) + } + + for (const modelID of requirementModels) { + const result = getModelCapabilities({ + providerID: "test-provider", + modelID, + bundledSnapshot, + }) + + expect(result.diagnostics.resolutionMode).toBe("snapshot-backed") + expect(result.diagnostics.snapshot.source).toBe("bundled-snapshot") + } + }) +}) diff --git a/src/shared/model-capabilities.ts b/src/shared/model-capabilities.ts new file mode 100644 index 000000000..0a9749243 --- /dev/null +++ b/src/shared/model-capabilities.ts @@ -0,0 +1,462 @@ +import bundledModelCapabilitiesSnapshotJson from "../generated/model-capabilities.generated.json" +import { findProviderModelMetadata, type ModelMetadata } from "./connected-providers-cache" +import { resolveModelIDAlias } from "./model-capability-aliases" +import { detectHeuristicModelFamily } from "./model-capability-heuristics" + +export type ModelCapabilitiesSnapshotEntry = { + id: string + family?: string + reasoning?: boolean + temperature?: boolean + toolCall?: boolean + modalities?: { + input?: string[] + output?: string[] + } + limit?: { + context?: number + input?: number + output?: number + } +} + +export type ModelCapabilitiesSnapshot = { + generatedAt: string + sourceUrl: string + models: Record +} + +export type ModelCapabilities = { + requestedModelID: string + canonicalModelID: string + family?: string + variants?: string[] + reasoningEfforts?: string[] + reasoning?: boolean + supportsThinking?: boolean + supportsTemperature?: boolean + supportsTopP?: boolean + maxOutputTokens?: number + toolCall?: boolean + modalities?: { + input?: string[] + output?: string[] + } + diagnostics: ModelCapabilitiesDiagnostics +} + +type GetModelCapabilitiesInput = { + providerID: string + modelID: string + runtimeModel?: ModelMetadata | Record + runtimeSnapshot?: ModelCapabilitiesSnapshot + bundledSnapshot?: ModelCapabilitiesSnapshot +} + +type ModelCapabilityOverride = { + variants?: string[] + reasoningEfforts?: string[] + supportsThinking?: boolean + supportsTemperature?: boolean + supportsTopP?: boolean +} + +type DiagnosticSource = + | "none" + | "runtime" + | "runtime-snapshot" + | "bundled-snapshot" + | "override" + | "heuristic" + | "canonical" + | "exact-alias" + | "pattern-alias" + +export type ModelCapabilitiesDiagnostics = { + resolutionMode: "snapshot-backed" | "alias-backed" | "heuristic-backed" | "unknown" + canonicalization: { + source: "canonical" | "exact-alias" | "pattern-alias" + ruleID?: string + } + snapshot: { + source: "runtime-snapshot" | "bundled-snapshot" | "none" + } + family: { source: "snapshot" | "heuristic" | "none" } + variants: { source: Exclude } + reasoningEfforts: { source: Exclude } + reasoning: { source: "runtime" | "runtime-snapshot" | "bundled-snapshot" | "none" } + supportsThinking: { source: "runtime" | "override" | "heuristic" | "runtime-snapshot" | "bundled-snapshot" | "none" } + supportsTemperature: { source: "runtime" | "override" | "runtime-snapshot" | "bundled-snapshot" | "none" } + supportsTopP: { source: "runtime" | "override" | "none" } + maxOutputTokens: { source: "runtime" | "runtime-snapshot" | "bundled-snapshot" | "none" } + toolCall: { source: "runtime" | "runtime-snapshot" | "bundled-snapshot" | "none" } + modalities: { source: "runtime" | "runtime-snapshot" | "bundled-snapshot" | "none" } +} + +const MODEL_ID_OVERRIDES: Record = {} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} + +function normalizeLookupModelID(modelID: string): string { + return modelID.trim().toLowerCase() +} + +function readBoolean(value: unknown): boolean | undefined { + return typeof value === "boolean" ? value : undefined +} + +function readNumber(value: unknown): number | undefined { + return typeof value === "number" ? value : undefined +} + +function readStringArray(value: unknown): string[] | undefined { + if (!Array.isArray(value)) { + return undefined + } + + const strings = value.filter((item): item is string => typeof item === "string") + return strings.length > 0 ? strings : undefined +} + +function normalizeVariantKeys(value: unknown): string[] | undefined { + const arrayVariants = readStringArray(value) + if (arrayVariants) { + return arrayVariants.map((variant) => variant.toLowerCase()) + } + + if (!isRecord(value)) { + return undefined + } + + const variants = Object.keys(value).map((variant) => variant.toLowerCase()) + return variants.length > 0 ? variants : undefined +} + +function readModalityKeys(value: unknown): string[] | undefined { + const stringArray = readStringArray(value) + if (stringArray) { + return stringArray.map((entry) => entry.toLowerCase()) + } + + if (!isRecord(value)) { + return undefined + } + + const enabled = Object.entries(value) + .filter(([, supported]) => supported === true) + .map(([modality]) => modality.toLowerCase()) + + return enabled.length > 0 ? enabled : undefined +} + +function normalizeModalities(value: unknown): ModelCapabilities["modalities"] | undefined { + if (!isRecord(value)) { + return undefined + } + + const input = readModalityKeys(value.input) + const output = readModalityKeys(value.output) + + if (!input && !output) { + return undefined + } + + return { + ...(input ? { input } : {}), + ...(output ? { output } : {}), + } +} + +function normalizeSnapshot(snapshot: ModelCapabilitiesSnapshot | typeof bundledModelCapabilitiesSnapshotJson): ModelCapabilitiesSnapshot { + return snapshot as ModelCapabilitiesSnapshot +} + +function getOverride(modelID: string): ModelCapabilityOverride | undefined { + return MODEL_ID_OVERRIDES[normalizeLookupModelID(modelID)] +} + +function readRuntimeModelCapabilities(runtimeModel: Record | undefined): Record | undefined { + return isRecord(runtimeModel?.capabilities) ? runtimeModel.capabilities : undefined +} + +function readRuntimeModelLimitOutput(runtimeModel: Record | undefined): number | undefined { + if (!runtimeModel) { + return undefined + } + + const limit = isRecord(runtimeModel.limit) + ? runtimeModel.limit + : readRuntimeModelCapabilities(runtimeModel)?.limit + if (!isRecord(limit)) { + return undefined + } + + return readNumber(limit.output) +} + +function readRuntimeModelBoolean(runtimeModel: Record | undefined, keys: string[]): boolean | undefined { + if (!runtimeModel) { + return undefined + } + + const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) + + for (const key of keys) { + const value = runtimeModel[key] + if (typeof value === "boolean") { + return value + } + + const capabilityValue = runtimeCapabilities?.[key] + if (typeof capabilityValue === "boolean") { + return capabilityValue + } + } + + return undefined +} + +function readRuntimeModelModalities(runtimeModel: Record | undefined): ModelCapabilities["modalities"] | undefined { + if (!runtimeModel) { + return undefined + } + + const rootModalities = normalizeModalities(runtimeModel.modalities) + if (rootModalities) { + return rootModalities + } + + const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) + if (!runtimeCapabilities) { + return undefined + } + + const nestedModalities = normalizeModalities(runtimeCapabilities.modalities) + if (nestedModalities) { + return nestedModalities + } + + const capabilityModalities = normalizeModalities(runtimeCapabilities) + if (capabilityModalities) { + return capabilityModalities + } + + return undefined +} + +function readRuntimeModelVariants(runtimeModel: Record | undefined): string[] | undefined { + if (!runtimeModel) { + return undefined + } + + const rootVariants = normalizeVariantKeys(runtimeModel.variants) + if (rootVariants) { + return rootVariants + } + + const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) + if (!runtimeCapabilities) { + return undefined + } + + return normalizeVariantKeys(runtimeCapabilities.variants) +} + +function readRuntimeModelTopPSupport(runtimeModel: Record | undefined): boolean | undefined { + return readRuntimeModelBoolean(runtimeModel, ["topP", "top_p"]) +} + +function readRuntimeModelToolCallSupport(runtimeModel: Record | undefined): boolean | undefined { + return readRuntimeModelBoolean(runtimeModel, ["toolCall", "tool_call", "toolcall"]) +} + +function readRuntimeModelReasoningSupport(runtimeModel: Record | undefined): boolean | undefined { + return readRuntimeModelBoolean(runtimeModel, ["reasoning"]) +} + +function readRuntimeModelTemperatureSupport(runtimeModel: Record | undefined): boolean | undefined { + return readRuntimeModelBoolean(runtimeModel, ["temperature"]) +} + +function readRuntimeModelThinkingSupport(runtimeModel: Record | undefined): boolean | undefined { + const capabilityValue = readRuntimeModelReasoningSupport(runtimeModel) + if (capabilityValue !== undefined) { + return capabilityValue + } + + const rootThinkingSupport = readRuntimeModelBoolean(runtimeModel, ["thinking", "supportsThinking"]) + if (rootThinkingSupport !== undefined) { + return rootThinkingSupport + } + + const runtimeCapabilities = readRuntimeModelCapabilities(runtimeModel) + if (!runtimeCapabilities) { + return undefined + } + + for (const key of ["thinking", "supportsThinking"] as const) { + const value = runtimeCapabilities[key] + if (typeof value === "boolean") { + return value + } + } + + return undefined +} + +function readRuntimeModel(runtimeModel: ModelMetadata | Record | undefined): Record | undefined { + return isRecord(runtimeModel) ? runtimeModel : undefined +} + +const bundledModelCapabilitiesSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) + +export function getBundledModelCapabilitiesSnapshot(): ModelCapabilitiesSnapshot { + return bundledModelCapabilitiesSnapshot +} + +export function getModelCapabilities(input: GetModelCapabilitiesInput): ModelCapabilities { + const canonicalization = resolveModelIDAlias(input.modelID) + const requestedModelID = canonicalization.requestedModelID + const canonicalModelID = canonicalization.canonicalModelID + const override = getOverride(input.modelID) + const runtimeModel = readRuntimeModel( + input.runtimeModel ?? findProviderModelMetadata(input.providerID, input.modelID), + ) + const runtimeSnapshot = input.runtimeSnapshot + const bundledSnapshot = input.bundledSnapshot ?? bundledModelCapabilitiesSnapshot + const snapshotEntry = runtimeSnapshot?.models?.[canonicalModelID] ?? bundledSnapshot.models[canonicalModelID] + const heuristicFamily = detectHeuristicModelFamily(canonicalModelID) + const runtimeVariants = readRuntimeModelVariants(runtimeModel) + const snapshotSource: ModelCapabilitiesDiagnostics["snapshot"]["source"] = + runtimeSnapshot?.models?.[canonicalModelID] + ? "runtime-snapshot" + : bundledSnapshot.models[canonicalModelID] + ? "bundled-snapshot" + : "none" + const familySource: ModelCapabilitiesDiagnostics["family"]["source"] = + snapshotEntry?.family + ? "snapshot" + : heuristicFamily?.family + ? "heuristic" + : "none" + const variantsSource: ModelCapabilitiesDiagnostics["variants"]["source"] = + runtimeVariants + ? "runtime" + : override?.variants + ? "override" + : heuristicFamily?.variants + ? "heuristic" + : "none" + const reasoningEffortsSource: ModelCapabilitiesDiagnostics["reasoningEfforts"]["source"] = + override?.reasoningEfforts + ? "override" + : heuristicFamily?.reasoningEfforts + ? "heuristic" + : "none" + const reasoningSource: ModelCapabilitiesDiagnostics["reasoning"]["source"] = + readRuntimeModelReasoningSupport(runtimeModel) !== undefined + ? "runtime" + : snapshotEntry?.reasoning !== undefined + ? snapshotSource + : "none" + const supportsThinkingSource: ModelCapabilitiesDiagnostics["supportsThinking"]["source"] = + override?.supportsThinking !== undefined + ? "override" + : heuristicFamily?.supportsThinking !== undefined + ? "heuristic" + : readRuntimeModelThinkingSupport(runtimeModel) !== undefined + ? "runtime" + : snapshotEntry?.reasoning !== undefined + ? snapshotSource + : "none" + const supportsTemperatureSource: ModelCapabilitiesDiagnostics["supportsTemperature"]["source"] = + readRuntimeModelTemperatureSupport(runtimeModel) !== undefined + ? "runtime" + : override?.supportsTemperature !== undefined + ? "override" + : snapshotEntry?.temperature !== undefined + ? snapshotSource + : "none" + const supportsTopPSource: ModelCapabilitiesDiagnostics["supportsTopP"]["source"] = + readRuntimeModelTopPSupport(runtimeModel) !== undefined + ? "runtime" + : override?.supportsTopP !== undefined + ? "override" + : "none" + const maxOutputTokensSource: ModelCapabilitiesDiagnostics["maxOutputTokens"]["source"] = + readRuntimeModelLimitOutput(runtimeModel) !== undefined + ? "runtime" + : snapshotEntry?.limit?.output !== undefined + ? snapshotSource + : "none" + const toolCallSource: ModelCapabilitiesDiagnostics["toolCall"]["source"] = + readRuntimeModelToolCallSupport(runtimeModel) !== undefined + ? "runtime" + : snapshotEntry?.toolCall !== undefined + ? snapshotSource + : "none" + const modalitiesSource: ModelCapabilitiesDiagnostics["modalities"]["source"] = + readRuntimeModelModalities(runtimeModel) !== undefined + ? "runtime" + : snapshotEntry?.modalities !== undefined + ? snapshotSource + : "none" + const resolutionMode: ModelCapabilitiesDiagnostics["resolutionMode"] = + snapshotSource !== "none" && canonicalization.source === "canonical" + ? "snapshot-backed" + : snapshotSource !== "none" + ? "alias-backed" + : familySource === "heuristic" || variantsSource === "heuristic" || reasoningEffortsSource === "heuristic" + ? "heuristic-backed" + : "unknown" + + return { + requestedModelID, + canonicalModelID, + family: snapshotEntry?.family ?? heuristicFamily?.family, + variants: runtimeVariants ?? override?.variants ?? heuristicFamily?.variants, + reasoningEfforts: override?.reasoningEfforts ?? heuristicFamily?.reasoningEfforts, + reasoning: readRuntimeModelReasoningSupport(runtimeModel) ?? snapshotEntry?.reasoning, + supportsThinking: + override?.supportsThinking + ?? heuristicFamily?.supportsThinking + ?? readRuntimeModelThinkingSupport(runtimeModel) + ?? snapshotEntry?.reasoning, + supportsTemperature: + readRuntimeModelTemperatureSupport(runtimeModel) + ?? override?.supportsTemperature + ?? snapshotEntry?.temperature, + supportsTopP: + readRuntimeModelTopPSupport(runtimeModel) + ?? override?.supportsTopP, + maxOutputTokens: + readRuntimeModelLimitOutput(runtimeModel) + ?? snapshotEntry?.limit?.output, + toolCall: + readRuntimeModelToolCallSupport(runtimeModel) + ?? snapshotEntry?.toolCall, + modalities: + readRuntimeModelModalities(runtimeModel) + ?? snapshotEntry?.modalities, + diagnostics: { + resolutionMode, + canonicalization: { + source: canonicalization.source, + ...(canonicalization.ruleID ? { ruleID: canonicalization.ruleID } : {}), + }, + snapshot: { source: snapshotSource }, + family: { source: familySource }, + variants: { source: variantsSource }, + reasoningEfforts: { source: reasoningEffortsSource }, + reasoning: { source: reasoningSource }, + supportsThinking: { source: supportsThinkingSource }, + supportsTemperature: { source: supportsTemperatureSource }, + supportsTopP: { source: supportsTopPSource }, + maxOutputTokens: { source: maxOutputTokensSource }, + toolCall: { source: toolCallSource }, + modalities: { source: modalitiesSource }, + }, + } +} diff --git a/src/shared/model-capability-aliases.test.ts b/src/shared/model-capability-aliases.test.ts new file mode 100644 index 000000000..9e563fc02 --- /dev/null +++ b/src/shared/model-capability-aliases.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, test } from "bun:test" + +import { resolveModelIDAlias } from "./model-capability-aliases" + +describe("model-capability-aliases", () => { + test("keeps canonical model IDs unchanged", () => { + const result = resolveModelIDAlias("gpt-5.4") + + expect(result).toEqual({ + requestedModelID: "gpt-5.4", + canonicalModelID: "gpt-5.4", + source: "canonical", + }) + }) + + test("normalizes exact local tier aliases to canonical models.dev IDs", () => { + const result = resolveModelIDAlias("gemini-3.1-pro-high") + + expect(result).toEqual({ + requestedModelID: "gemini-3.1-pro-high", + canonicalModelID: "gemini-3.1-pro", + source: "exact-alias", + ruleID: "gemini-3.1-pro-tier-alias", + }) + }) + + test("does not resolve prototype keys as aliases", () => { + const result = resolveModelIDAlias("constructor") + + expect(result).toEqual({ + requestedModelID: "constructor", + canonicalModelID: "constructor", + source: "canonical", + }) + }) + + test("normalizes legacy Claude thinking aliases through a named exact rule", () => { + const result = resolveModelIDAlias("claude-opus-4-6-thinking") + + expect(result).toEqual({ + requestedModelID: "claude-opus-4-6-thinking", + canonicalModelID: "claude-opus-4-6", + source: "exact-alias", + ruleID: "claude-opus-4-6-thinking-legacy-alias", + }) + }) +}) diff --git a/src/shared/model-capability-aliases.ts b/src/shared/model-capability-aliases.ts new file mode 100644 index 000000000..953b5a300 --- /dev/null +++ b/src/shared/model-capability-aliases.ts @@ -0,0 +1,103 @@ +export type ExactAliasRule = { + aliasModelID: string + ruleID: string + canonicalModelID: string + rationale: string +} + +export type PatternAliasRule = { + ruleID: string + description: string + match: (normalizedModelID: string) => boolean + canonicalize: (normalizedModelID: string) => string +} + +export type ModelIDAliasResolution = { + requestedModelID: string + canonicalModelID: string + source: "canonical" | "exact-alias" | "pattern-alias" + ruleID?: string +} + +const EXACT_ALIAS_RULES: ReadonlyArray = [ + { + aliasModelID: "gemini-3.1-pro-high", + ruleID: "gemini-3.1-pro-tier-alias", + canonicalModelID: "gemini-3.1-pro", + rationale: "OmO historically encoded Gemini tier selection in the model name instead of variant metadata.", + }, + { + aliasModelID: "gemini-3.1-pro-low", + ruleID: "gemini-3.1-pro-tier-alias", + canonicalModelID: "gemini-3.1-pro", + rationale: "OmO historically encoded Gemini tier selection in the model name instead of variant metadata.", + }, + { + aliasModelID: "gemini-3-pro-high", + ruleID: "gemini-3-pro-tier-alias", + canonicalModelID: "gemini-3-pro-preview", + rationale: "Legacy Gemini 3 tier suffixes still need to land on the canonical preview model.", + }, + { + aliasModelID: "gemini-3-pro-low", + ruleID: "gemini-3-pro-tier-alias", + canonicalModelID: "gemini-3-pro-preview", + rationale: "Legacy Gemini 3 tier suffixes still need to land on the canonical preview model.", + }, + { + aliasModelID: "claude-opus-4-6-thinking", + ruleID: "claude-opus-4-6-thinking-legacy-alias", + canonicalModelID: "claude-opus-4-6", + rationale: "OmO historically used a legacy compatibility suffix before models.dev shipped canonical thinking variants for newer Claude families.", + }, +] + +const EXACT_ALIAS_RULES_BY_MODEL: ReadonlyMap = new Map( + EXACT_ALIAS_RULES.map((rule) => [rule.aliasModelID, rule]), +) + +const PATTERN_ALIAS_RULES: ReadonlyArray = [] + +function normalizeLookupModelID(modelID: string): string { + return modelID.trim().toLowerCase() +} + +export function resolveModelIDAlias(modelID: string): ModelIDAliasResolution { + const normalizedModelID = normalizeLookupModelID(modelID) + const exactRule = EXACT_ALIAS_RULES_BY_MODEL.get(normalizedModelID) + if (exactRule) { + return { + requestedModelID: normalizedModelID, + canonicalModelID: exactRule.canonicalModelID, + source: "exact-alias", + ruleID: exactRule.ruleID, + } + } + + for (const rule of PATTERN_ALIAS_RULES) { + if (!rule.match(normalizedModelID)) { + continue + } + + return { + requestedModelID: normalizedModelID, + canonicalModelID: rule.canonicalize(normalizedModelID), + source: "pattern-alias", + ruleID: rule.ruleID, + } + } + + return { + requestedModelID: normalizedModelID, + canonicalModelID: normalizedModelID, + source: "canonical", + } +} + +export function getExactModelIDAliasRules(): ReadonlyArray { + return EXACT_ALIAS_RULES +} + +export function getPatternModelIDAliasRules(): ReadonlyArray { + return PATTERN_ALIAS_RULES +} diff --git a/src/shared/model-capability-guardrails.test.ts b/src/shared/model-capability-guardrails.test.ts new file mode 100644 index 000000000..06a9c07eb --- /dev/null +++ b/src/shared/model-capability-guardrails.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, test } from "bun:test" + +import type { ModelCapabilitiesSnapshot } from "./model-capabilities" +import { getBundledModelCapabilitiesSnapshot } from "./model-capabilities" +import { + collectModelCapabilityGuardrailIssues, + getBuiltInRequirementModelIDs, +} from "./model-capability-guardrails" + +describe("model-capability-guardrails", () => { + test("keeps the current alias registry and built-in requirements aligned with the bundled snapshot", () => { + const issues = collectModelCapabilityGuardrailIssues() + + expect(issues).toEqual([]) + }) + + test("requires built-in requirement models to stay unique and sorted", () => { + const modelIDs = getBuiltInRequirementModelIDs() + + expect(modelIDs).toEqual([...modelIDs].sort()) + expect(new Set(modelIDs).size).toBe(modelIDs.length) + expect(modelIDs).toContain("claude-opus-4-6") + expect(modelIDs).toContain("gpt-5.4") + expect(modelIDs).toContain("kimi-k2.5") + }) + + test("flags exact aliases whose canonical target disappears from the snapshot", () => { + const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const brokenSnapshot: ModelCapabilitiesSnapshot = { + ...bundledSnapshot, + models: Object.fromEntries( + Object.entries(bundledSnapshot.models).filter(([modelID]) => modelID !== "gemini-3.1-pro"), + ), + } + + const issues = collectModelCapabilityGuardrailIssues({ + snapshot: brokenSnapshot, + requirementModelIDs: [], + }) + + expect(issues).toContainEqual( + expect.objectContaining({ + kind: "alias-target-missing-from-snapshot", + aliasModelID: "gemini-3.1-pro-high", + canonicalModelID: "gemini-3.1-pro", + }), + ) + }) + + test("flags exact aliases when models.dev gains a canonical entry for the alias itself", () => { + const bundledSnapshot = getBundledModelCapabilitiesSnapshot() + const aliasCollisionSnapshot: ModelCapabilitiesSnapshot = { + ...bundledSnapshot, + models: { + ...bundledSnapshot.models, + "gemini-3.1-pro-high": { + id: "gemini-3.1-pro-high", + family: "gemini", + reasoning: true, + }, + }, + } + + const issues = collectModelCapabilityGuardrailIssues({ + snapshot: aliasCollisionSnapshot, + requirementModelIDs: [], + }) + + expect(issues).toContainEqual( + expect.objectContaining({ + kind: "exact-alias-collides-with-snapshot", + aliasModelID: "gemini-3.1-pro-high", + canonicalModelID: "gemini-3.1-pro", + }), + ) + }) + + test("flags built-in requirement models that rely on aliases instead of canonical IDs", () => { + const issues = collectModelCapabilityGuardrailIssues({ + requirementModelIDs: ["gemini-3.1-pro-high"], + }) + + expect(issues).toContainEqual( + expect.objectContaining({ + kind: "built-in-model-relies-on-alias", + modelID: "gemini-3.1-pro-high", + canonicalModelID: "gemini-3.1-pro", + ruleID: "gemini-3.1-pro-tier-alias", + }), + ) + }) +}) diff --git a/src/shared/model-capability-guardrails.ts b/src/shared/model-capability-guardrails.ts new file mode 100644 index 000000000..b1c74feae --- /dev/null +++ b/src/shared/model-capability-guardrails.ts @@ -0,0 +1,149 @@ +import type { ModelCapabilitiesSnapshot } from "./model-capabilities" +import { getBundledModelCapabilitiesSnapshot } from "./model-capabilities" +import { + getExactModelIDAliasRules, + getPatternModelIDAliasRules, + resolveModelIDAlias, +} from "./model-capability-aliases" +import { AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS } from "./model-requirements" + +export type ModelCapabilityGuardrailIssue = + | { + kind: "alias-target-missing-from-snapshot" + ruleID: string + aliasModelID: string + canonicalModelID: string + message: string + } + | { + kind: "exact-alias-collides-with-snapshot" + ruleID: string + aliasModelID: string + canonicalModelID: string + message: string + } + | { + kind: "pattern-alias-collides-with-snapshot" + ruleID: string + modelID: string + canonicalModelID: string + message: string + } + | { + kind: "built-in-model-relies-on-alias" + modelID: string + canonicalModelID: string + ruleID: string + message: string + } + | { + kind: "built-in-model-missing-from-snapshot" + modelID: string + canonicalModelID: string + message: string + } + +type CollectModelCapabilityGuardrailIssuesInput = { + snapshot?: ModelCapabilitiesSnapshot + requirementModelIDs?: Iterable +} + +function normalizeLookupModelID(modelID: string): string { + return modelID.trim().toLowerCase() +} + +export function getBuiltInRequirementModelIDs(): string[] { + const modelIDs = new Set() + + for (const requirement of Object.values(AGENT_MODEL_REQUIREMENTS)) { + for (const entry of requirement.fallbackChain) { + modelIDs.add(entry.model) + } + } + + for (const requirement of Object.values(CATEGORY_MODEL_REQUIREMENTS)) { + for (const entry of requirement.fallbackChain) { + modelIDs.add(entry.model) + } + } + + return [...modelIDs].sort() +} + +export function collectModelCapabilityGuardrailIssues( + input: CollectModelCapabilityGuardrailIssuesInput = {}, +): ModelCapabilityGuardrailIssue[] { + const snapshot = input.snapshot ?? getBundledModelCapabilitiesSnapshot() + const snapshotModelIDs = new Set( + Object.keys(snapshot.models).map((modelID) => normalizeLookupModelID(modelID)), + ) + const requirementModelIDs = input.requirementModelIDs ?? getBuiltInRequirementModelIDs() + const issues: ModelCapabilityGuardrailIssue[] = [] + + for (const rule of getExactModelIDAliasRules()) { + if (!snapshotModelIDs.has(rule.canonicalModelID)) { + issues.push({ + kind: "alias-target-missing-from-snapshot", + ruleID: rule.ruleID, + aliasModelID: rule.aliasModelID, + canonicalModelID: rule.canonicalModelID, + message: `Alias ${rule.aliasModelID} points to missing snapshot model ${rule.canonicalModelID}.`, + }) + } + + if (snapshotModelIDs.has(rule.aliasModelID)) { + issues.push({ + kind: "exact-alias-collides-with-snapshot", + ruleID: rule.ruleID, + aliasModelID: rule.aliasModelID, + canonicalModelID: rule.canonicalModelID, + message: `Alias ${rule.aliasModelID} now exists in models.dev and should be reviewed instead of force-mapping to ${rule.canonicalModelID}.`, + }) + } + } + + for (const rule of getPatternModelIDAliasRules()) { + for (const modelID of snapshotModelIDs) { + if (!rule.match(modelID)) { + continue + } + + const canonicalModelID = rule.canonicalize(modelID) + if (canonicalModelID === modelID) { + continue + } + + issues.push({ + kind: "pattern-alias-collides-with-snapshot", + ruleID: rule.ruleID, + modelID, + canonicalModelID, + message: `Pattern alias ${rule.ruleID} would rewrite canonical snapshot model ${modelID} to ${canonicalModelID}.`, + }) + } + } + + for (const modelID of requirementModelIDs) { + const aliasResolution = resolveModelIDAlias(modelID) + if (aliasResolution.source !== "canonical") { + issues.push({ + kind: "built-in-model-relies-on-alias", + modelID: aliasResolution.requestedModelID, + canonicalModelID: aliasResolution.canonicalModelID, + ruleID: aliasResolution.ruleID ?? "unknown-alias-rule", + message: `Built-in requirement model ${aliasResolution.requestedModelID} should be canonical and not rely on alias rule ${aliasResolution.ruleID}.`, + }) + } + + if (!snapshotModelIDs.has(aliasResolution.canonicalModelID)) { + issues.push({ + kind: "built-in-model-missing-from-snapshot", + modelID: aliasResolution.requestedModelID, + canonicalModelID: aliasResolution.canonicalModelID, + message: `Built-in requirement model ${aliasResolution.requestedModelID} resolves to ${aliasResolution.canonicalModelID}, which is missing from the bundled snapshot.`, + }) + } + } + + return issues +} diff --git a/src/shared/model-capability-heuristics.ts b/src/shared/model-capability-heuristics.ts new file mode 100644 index 000000000..374c185ea --- /dev/null +++ b/src/shared/model-capability-heuristics.ts @@ -0,0 +1,93 @@ +import { normalizeModelID } from "./model-normalization" + +export type HeuristicModelFamilyDefinition = { + family: string + includes?: string[] + pattern?: RegExp + variants?: string[] + reasoningEfforts?: string[] + supportsThinking?: boolean +} + +export const HEURISTIC_MODEL_FAMILY_REGISTRY: ReadonlyArray = [ + { + family: "claude-opus", + pattern: /claude(?:-\d+(?:-\d+)*)?-opus/, + variants: ["low", "medium", "high", "max"], + supportsThinking: true, + }, + { + family: "claude-non-opus", + includes: ["claude"], + variants: ["low", "medium", "high"], + supportsThinking: true, + }, + { + family: "openai-reasoning", + pattern: /(?:^|\/)o\d(?:$|-)/, + variants: ["low", "medium", "high"], + reasoningEfforts: ["none", "minimal", "low", "medium", "high"], + }, + { + family: "gpt-5", + includes: ["gpt-5"], + variants: ["low", "medium", "high", "xhigh"], + reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh"], + }, + { + family: "gpt-legacy", + includes: ["gpt"], + variants: ["low", "medium", "high"], + }, + { + family: "gemini", + includes: ["gemini"], + variants: ["low", "medium", "high"], + }, + { + family: "kimi", + includes: ["kimi", "k2"], + variants: ["low", "medium", "high"], + }, + { + family: "glm", + includes: ["glm"], + variants: ["low", "medium", "high"], + }, + { + family: "minimax", + includes: ["minimax"], + variants: ["low", "medium", "high"], + }, + { + family: "deepseek", + includes: ["deepseek"], + variants: ["low", "medium", "high"], + }, + { + family: "mistral", + includes: ["mistral", "codestral"], + variants: ["low", "medium", "high"], + }, + { + family: "llama", + includes: ["llama"], + variants: ["low", "medium", "high"], + }, +] + +export function detectHeuristicModelFamily(modelID: string): HeuristicModelFamilyDefinition | undefined { + const normalizedModelID = normalizeModelID(modelID).toLowerCase() + + for (const definition of HEURISTIC_MODEL_FAMILY_REGISTRY) { + if (definition.pattern?.test(normalizedModelID)) { + return definition + } + + if (definition.includes?.some((value) => normalizedModelID.includes(value))) { + return definition + } + } + + return undefined +} diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index d69de0ef5..470dfea3a 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -64,23 +64,23 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("big-pickle") }) - test("librarian has valid fallbackChain with opencode-go/minimax-m2.5 as primary", () => { + test("librarian has valid fallbackChain with opencode-go/minimax-m2.7 as primary", () => { // given - librarian agent requirement const librarian = AGENT_MODEL_REQUIREMENTS["librarian"] // when - accessing librarian requirement - // then - fallbackChain exists with opencode-go/minimax-m2.5 as first entry + // then - fallbackChain exists with opencode-go/minimax-m2.7 as first entry expect(librarian).toBeDefined() expect(librarian.fallbackChain).toBeArray() expect(librarian.fallbackChain.length).toBeGreaterThan(0) const primary = librarian.fallbackChain[0] expect(primary.providers[0]).toBe("opencode-go") - expect(primary.model).toBe("minimax-m2.5") + expect(primary.model).toBe("minimax-m2.7") const second = librarian.fallbackChain[1] expect(second.providers[0]).toBe("opencode") - expect(second.model).toBe("minimax-m2.5-free") + expect(second.model).toBe("minimax-m2.5") const tertiary = librarian.fallbackChain[2] expect(tertiary.providers).toContain("anthropic") @@ -95,22 +95,22 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const explore = AGENT_MODEL_REQUIREMENTS["explore"] // when - accessing explore requirement - // then - fallbackChain: grok → opencode-go/minimax → minimax-free → haiku → nano expect(explore).toBeDefined() expect(explore.fallbackChain).toBeArray() expect(explore.fallbackChain).toHaveLength(5) const primary = explore.fallbackChain[0] expect(primary.providers).toContain("github-copilot") + expect(primary.providers).toContain("xai") expect(primary.model).toBe("grok-code-fast-1") const secondary = explore.fallbackChain[1] expect(secondary.providers).toContain("opencode-go") - expect(secondary.model).toBe("minimax-m2.5") + expect(secondary.model).toBe("minimax-m2.7") const tertiary = explore.fallbackChain[2] expect(tertiary.providers).toContain("opencode") - expect(tertiary.model).toBe("minimax-m2.5-free") + expect(tertiary.model).toBe("minimax-m2.5") const quaternary = explore.fallbackChain[3] expect(quaternary.providers).toContain("anthropic") @@ -211,7 +211,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { // then - fallbackChain exists with claude-sonnet-4-6 as first entry expect(atlas).toBeDefined() expect(atlas.fallbackChain).toBeArray() - expect(atlas.fallbackChain.length).toBeGreaterThan(0) + expect(atlas.fallbackChain).toHaveLength(4) const primary = atlas.fallbackChain[0] expect(primary.model).toBe("claude-sonnet-4-6") @@ -227,15 +227,20 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { model: "gpt-5.4", variant: "medium", }) + + const quaternary = atlas.fallbackChain[3] + expect(quaternary.model).toBe("minimax-m2.7") + expect(quaternary.providers[0]).toBe("opencode-go") }) - test("sisyphus-junior has an OpenAI fallback before big-pickle", () => { + test("sisyphus-junior has an OpenAI fallback and minimax before big-pickle", () => { // given - sisyphus-junior agent requirement const sisyphusJunior = AGENT_MODEL_REQUIREMENTS["sisyphus-junior"] // when - locating the OpenAI fallback entry const openAiFallback = sisyphusJunior.fallbackChain.find((entry) => entry.providers.includes("openai")) const openAiFallbackIndex = sisyphusJunior.fallbackChain.findIndex((entry) => entry.providers.includes("openai")) + const minimaxIndex = sisyphusJunior.fallbackChain.findIndex((entry) => entry.model === "minimax-m2.7") const bigPickleIndex = sisyphusJunior.fallbackChain.findIndex((entry) => entry.model === "big-pickle") // then @@ -245,7 +250,8 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { variant: "medium", }) expect(openAiFallbackIndex).toBeGreaterThan(-1) - expect(bigPickleIndex).toBeGreaterThan(openAiFallbackIndex) + expect(minimaxIndex).toBeGreaterThan(openAiFallbackIndex) + expect(bigPickleIndex).toBeGreaterThan(minimaxIndex) }) test("hephaestus supports openai, github-copilot, venice, and opencode providers", () => { @@ -437,10 +443,10 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { const writing = CATEGORY_MODEL_REQUIREMENTS["writing"] // when - accessing writing requirement - // then - fallbackChain: gemini-3-flash -> kimi-k2.5 -> claude-sonnet-4-6 + // then - fallbackChain: gemini-3-flash -> kimi-k2.5 -> claude-sonnet-4-6 -> minimax-m2.7 expect(writing).toBeDefined() expect(writing.fallbackChain).toBeArray() - expect(writing.fallbackChain).toHaveLength(3) + expect(writing.fallbackChain).toHaveLength(4) const primary = writing.fallbackChain[0] expect(primary.model).toBe("gemini-3-flash") @@ -453,6 +459,10 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { const third = writing.fallbackChain[2] expect(third.model).toBe("claude-sonnet-4-6") expect(third.providers[0]).toBe("anthropic") + + const fourth = writing.fallbackChain[3] + expect(fourth.model).toBe("minimax-m2.7") + expect(fourth.providers[0]).toBe("opencode-go") }) test("all 8 categories have valid fallbackChain arrays", () => { diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index ea8a1cb91..ea413ea40 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -47,11 +47,10 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { hephaestus: { fallbackChain: [ { - providers: ["openai", "venice", "opencode"], - model: "gpt-5.3-codex", + providers: ["openai", "github-copilot", "venice", "opencode"], + model: "gpt-5.4", variant: "medium", }, - { providers: ["github-copilot"], model: "gpt-5.4", variant: "medium" }, ], requiresProvider: ["openai", "github-copilot", "venice", "opencode"], }, @@ -77,17 +76,17 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, librarian: { fallbackChain: [ - { providers: ["opencode-go"], model: "minimax-m2.5" }, - { providers: ["opencode"], model: "minimax-m2.5-free" }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, + { providers: ["opencode"], model: "minimax-m2.5" }, { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" }, { providers: ["opencode"], model: "gpt-5-nano" }, ], }, explore: { fallbackChain: [ - { providers: ["github-copilot"], model: "grok-code-fast-1" }, - { providers: ["opencode-go"], model: "minimax-m2.5" }, - { providers: ["opencode"], model: "minimax-m2.5-free" }, + { providers: ["github-copilot", "xai"], model: "grok-code-fast-1" }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, + { providers: ["opencode"], model: "minimax-m2.5" }, { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" }, { providers: ["opencode"], model: "gpt-5-nano" }, ], @@ -164,6 +163,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "gpt-5.4", variant: "medium", }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, ], }, "sisyphus-junior": { @@ -175,6 +175,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { model: "gpt-5.4", variant: "medium", }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, { providers: ["opencode"], model: "big-pickle" }, ], }, @@ -268,7 +269,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash", }, - { providers: ["opencode-go"], model: "minimax-m2.5" }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, { providers: ["opencode"], model: "gpt-5-nano" }, ], }, @@ -288,6 +289,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash", }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, ], }, "unspecified-high": { @@ -330,6 +332,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6", }, + { providers: ["opencode-go"], model: "minimax-m2.7" }, ], }, }; diff --git a/src/shared/model-settings-compatibility.test.ts b/src/shared/model-settings-compatibility.test.ts index 291da7547..ca31d9f1e 100644 --- a/src/shared/model-settings-compatibility.test.ts +++ b/src/shared/model-settings-compatibility.test.ts @@ -324,6 +324,27 @@ describe("resolveCompatibleModelSettings", () => { }) }) + test("GPT-5 downgrades unsupported max variant to xhigh", () => { + const result = resolveCompatibleModelSettings({ + providerID: "openai", + modelID: "gpt-5.4", + desired: { variant: "max" }, + }) + + expect(result).toEqual({ + variant: "xhigh", + reasoningEffort: undefined, + changes: [ + { + field: "variant", + from: "max", + to: "xhigh", + reason: "unsupported-by-model-family", + }, + ], + }) + }) + // Reasoning effort: "none" and "minimal" are valid per Vercel AI SDK test("GPT-5 keeps none reasoningEffort", () => { const result = resolveCompatibleModelSettings({ @@ -418,6 +439,63 @@ describe("resolveCompatibleModelSettings", () => { ]) }) + test("drops unsupported temperature when capability metadata disables it", () => { + const result = resolveCompatibleModelSettings({ + providerID: "openai", + modelID: "gpt-5.4", + desired: { temperature: 0.7 }, + capabilities: { supportsTemperature: false }, + }) + + expect(result.temperature).toBeUndefined() + expect(result.changes).toEqual([ + { + field: "temperature", + from: "0.7", + to: undefined, + reason: "unsupported-by-model-metadata", + }, + ]) + }) + + test("drops thinking when model capabilities say it is unsupported", () => { + const result = resolveCompatibleModelSettings({ + providerID: "openai", + modelID: "gpt-5.4", + desired: { thinking: { type: "enabled", budgetTokens: 4096 } }, + capabilities: { supportsThinking: false }, + }) + + expect(result.thinking).toBeUndefined() + expect(result.changes).toEqual([ + { + field: "thinking", + from: "{\"type\":\"enabled\",\"budgetTokens\":4096}", + to: undefined, + reason: "unsupported-by-model-metadata", + }, + ]) + }) + + test("clamps maxTokens to the model output limit", () => { + const result = resolveCompatibleModelSettings({ + providerID: "openai", + modelID: "gpt-5.4", + desired: { maxTokens: 200_000 }, + capabilities: { maxOutputTokens: 128_000 }, + }) + + expect(result.maxTokens).toBe(128_000) + expect(result.changes).toEqual([ + { + field: "maxTokens", + from: "200000", + to: "128000", + reason: "max-output-limit", + }, + ]) + }) + // Passthrough: undefined desired values produce no changes test("no-op when desired settings are empty", () => { const result = resolveCompatibleModelSettings({ diff --git a/src/shared/model-settings-compatibility.ts b/src/shared/model-settings-compatibility.ts index 3ed4c7587..89661c2b2 100644 --- a/src/shared/model-settings-compatibility.ts +++ b/src/shared/model-settings-compatibility.ts @@ -1,84 +1,56 @@ -import { normalizeModelID } from "./model-normalization" +import { detectHeuristicModelFamily } from "./model-capability-heuristics" -type CompatibilityField = "variant" | "reasoningEffort" +type CompatibilityField = "variant" | "reasoningEffort" | "temperature" | "topP" | "maxTokens" | "thinking" type DesiredModelSettings = { variant?: string reasoningEffort?: string + temperature?: number + topP?: number + maxTokens?: number + thinking?: Record } -type VariantCapabilities = { +type CompatibilityCapabilities = { variants?: string[] + reasoningEfforts?: string[] + supportsTemperature?: boolean + supportsTopP?: boolean + maxOutputTokens?: number + supportsThinking?: boolean } export type ModelSettingsCompatibilityInput = { providerID: string modelID: string desired: DesiredModelSettings - capabilities?: VariantCapabilities + capabilities?: CompatibilityCapabilities } export type ModelSettingsCompatibilityChange = { field: CompatibilityField from: string to?: string - reason: "unsupported-by-model-family" | "unknown-model-family" | "unsupported-by-model-metadata" + reason: + | "unsupported-by-model-family" + | "unknown-model-family" + | "unsupported-by-model-metadata" + | "max-output-limit" } export type ModelSettingsCompatibilityResult = { variant?: string reasoningEffort?: string + temperature?: number + topP?: number + maxTokens?: number + thinking?: Record changes: ModelSettingsCompatibilityChange[] } -// --------------------------------------------------------------------------- -// Unified model family registry — detection rules + capabilities in ONE row. -// New model family = one entry. Zero code changes anywhere else. -// Order matters: more-specific patterns first (claude-opus before claude). -// --------------------------------------------------------------------------- - -type FamilyDefinition = { - /** Substring(s) in normalised model ID that identify this family (OR) */ - includes?: string[] - /** Regex when substring matching isn't enough */ - pattern?: RegExp - /** Supported variant levels (ordered low -> max) */ - variants: string[] - /** Supported reasoning-effort levels. Omit = not supported. */ - reasoningEffort?: string[] -} - -const MODEL_FAMILY_REGISTRY: ReadonlyArray = [ - ["claude-opus", { pattern: /claude(?:-\d+(?:-\d+)*)?-opus/, variants: ["low", "medium", "high", "max"] }], - ["claude-non-opus", { includes: ["claude"], variants: ["low", "medium", "high"] }], - ["openai-reasoning", { pattern: /^o\d(?:$|-)/, variants: ["low", "medium", "high"], reasoningEffort: ["none", "minimal", "low", "medium", "high"] }], - ["gpt-5", { includes: ["gpt-5"], variants: ["low", "medium", "high", "xhigh", "max"], reasoningEffort: ["none", "minimal", "low", "medium", "high", "xhigh"] }], - ["gpt-legacy", { includes: ["gpt"], variants: ["low", "medium", "high"] }], - ["gemini", { includes: ["gemini"], variants: ["low", "medium", "high"] }], - ["kimi", { includes: ["kimi", "k2"], variants: ["low", "medium", "high"] }], - ["glm", { includes: ["glm"], variants: ["low", "medium", "high"] }], - ["minimax", { includes: ["minimax"], variants: ["low", "medium", "high"] }], - ["deepseek", { includes: ["deepseek"], variants: ["low", "medium", "high"] }], - ["mistral", { includes: ["mistral", "codestral"], variants: ["low", "medium", "high"] }], - ["llama", { includes: ["llama"], variants: ["low", "medium", "high"] }], -] - const VARIANT_LADDER = ["low", "medium", "high", "xhigh", "max"] const REASONING_LADDER = ["none", "minimal", "low", "medium", "high", "xhigh"] -// --------------------------------------------------------------------------- -// Model family detection — single pass over the registry -// --------------------------------------------------------------------------- - -function detectFamily(_providerID: string, modelID: string): FamilyDefinition | undefined { - const model = normalizeModelID(modelID).toLowerCase() - for (const [, def] of MODEL_FAMILY_REGISTRY) { - if (def.pattern?.test(model)) return def - if (def.includes?.some((s) => model.includes(s))) return def - } - return undefined -} - // --------------------------------------------------------------------------- // Generic resolution — one function for both fields // --------------------------------------------------------------------------- @@ -96,13 +68,20 @@ function downgradeWithinLadder(value: string, allowed: string[], ladder: string[ return undefined } -function normalizeCapabilitiesVariants(capabilities: VariantCapabilities | undefined): string[] | undefined { +function normalizeCapabilitiesVariants(capabilities: CompatibilityCapabilities | undefined): string[] | undefined { if (!capabilities?.variants || capabilities.variants.length === 0) { return undefined } return capabilities.variants.map((v) => v.toLowerCase()) } +function normalizeCapabilitiesReasoningEfforts(capabilities: CompatibilityCapabilities | undefined): string[] | undefined { + if (!capabilities?.reasoningEfforts || capabilities.reasoningEfforts.length === 0) { + return undefined + } + return capabilities.reasoningEfforts.map((value) => value.toLowerCase()) +} + type FieldResolution = { value?: string; reason?: ModelSettingsCompatibilityChange["reason"] } function resolveField( @@ -146,10 +125,11 @@ function resolveField( export function resolveCompatibleModelSettings( input: ModelSettingsCompatibilityInput, ): ModelSettingsCompatibilityResult { - const family = detectFamily(input.providerID, input.modelID) + const family = detectHeuristicModelFamily(input.modelID) const familyKnown = family !== undefined const changes: ModelSettingsCompatibilityChange[] = [] const metadataVariants = normalizeCapabilitiesVariants(input.capabilities) + const metadataReasoningEfforts = normalizeCapabilitiesReasoningEfforts(input.capabilities) let variant = input.desired.variant if (variant !== undefined) { @@ -164,12 +144,68 @@ export function resolveCompatibleModelSettings( let reasoningEffort = input.desired.reasoningEffort if (reasoningEffort !== undefined) { const normalized = reasoningEffort.toLowerCase() - const resolved = resolveField(normalized, family?.reasoningEffort, REASONING_LADDER, familyKnown) + const resolved = resolveField(normalized, family?.reasoningEfforts, REASONING_LADDER, familyKnown, metadataReasoningEfforts) if (resolved.value !== normalized && resolved.reason) { changes.push({ field: "reasoningEffort", from: reasoningEffort, to: resolved.value, reason: resolved.reason }) } reasoningEffort = resolved.value } - return { variant, reasoningEffort, changes } + let temperature = input.desired.temperature + if (temperature !== undefined && input.capabilities?.supportsTemperature === false) { + changes.push({ + field: "temperature", + from: String(temperature), + to: undefined, + reason: "unsupported-by-model-metadata", + }) + temperature = undefined + } + + let topP = input.desired.topP + if (topP !== undefined && input.capabilities?.supportsTopP === false) { + changes.push({ + field: "topP", + from: String(topP), + to: undefined, + reason: "unsupported-by-model-metadata", + }) + topP = undefined + } + + let maxTokens = input.desired.maxTokens + if ( + maxTokens !== undefined && + input.capabilities?.maxOutputTokens !== undefined && + maxTokens > input.capabilities.maxOutputTokens + ) { + changes.push({ + field: "maxTokens", + from: String(maxTokens), + to: String(input.capabilities.maxOutputTokens), + reason: "max-output-limit", + }) + maxTokens = input.capabilities.maxOutputTokens + } + + let thinking = input.desired.thinking + if (thinking !== undefined && input.capabilities?.supportsThinking === false) { + changes.push({ + field: "thinking", + from: JSON.stringify(thinking), + to: undefined, + reason: "unsupported-by-model-metadata", + }) + thinking = undefined + } + + return { + variant, + reasoningEffort, + ...(input.desired.temperature !== undefined ? { temperature } : {}), + ...(input.desired.topP !== undefined ? { topP } : {}), + ...(input.desired.maxTokens !== undefined ? { maxTokens } : {}), + ...(input.desired.thinking !== undefined ? { thinking } : {}), + changes, + } } diff --git a/src/shared/opencode-command-dirs.test.ts b/src/shared/opencode-command-dirs.test.ts index 02ffb871f..e75b0284c 100644 --- a/src/shared/opencode-command-dirs.test.ts +++ b/src/shared/opencode-command-dirs.test.ts @@ -26,8 +26,10 @@ describe("opencode-command-dirs", () => { const dirs = getOpenCodeSkillDirs({ binary: "opencode" }) expect(dirs).toContain("/home/user/.config/opencode/profiles/opus/skills") + expect(dirs).toContain("/home/user/.config/opencode/profiles/opus/skill") + expect(dirs).toContain("/home/user/.config/opencode/skill") expect(dirs).toContain("/home/user/.config/opencode/skills") - expect(dirs).toHaveLength(2) + expect(dirs).toHaveLength(4) }) }) }) @@ -41,7 +43,8 @@ describe("opencode-command-dirs", () => { const dirs = getOpenCodeSkillDirs({ binary: "opencode" }) expect(dirs).toContain("/home/user/.config/opencode/skills") - expect(dirs).toHaveLength(1) + expect(dirs).toContain("/home/user/.config/opencode/skill") + expect(dirs).toHaveLength(2) }) }) }) @@ -56,9 +59,11 @@ describe("opencode-command-dirs", () => { const { getOpenCodeCommandDirs } = await import("./opencode-command-dirs") const dirs = getOpenCodeCommandDirs({ binary: "opencode" }) + expect(dirs).toContain("/home/user/.config/opencode/profiles/opus/commands") expect(dirs).toContain("/home/user/.config/opencode/profiles/opus/command") + expect(dirs).toContain("/home/user/.config/opencode/commands") expect(dirs).toContain("/home/user/.config/opencode/command") - expect(dirs).toHaveLength(2) + expect(dirs).toHaveLength(4) }) }) }) diff --git a/src/shared/opencode-command-dirs.ts b/src/shared/opencode-command-dirs.ts index 456085730..34f2ecce1 100644 --- a/src/shared/opencode-command-dirs.ts +++ b/src/shared/opencode-command-dirs.ts @@ -14,11 +14,11 @@ function getParentOpencodeConfigDir(configDir: string): string | null { export function getOpenCodeCommandDirs(options: OpenCodeConfigDirOptions): string[] { const configDir = getOpenCodeConfigDir(options) const parentConfigDir = getParentOpencodeConfigDir(configDir) - return Array.from( new Set([ + join(configDir, "commands"), join(configDir, "command"), - ...(parentConfigDir ? [join(parentConfigDir, "command")] : []), + ...(parentConfigDir ? [join(parentConfigDir, "commands"), join(parentConfigDir, "command")] : []), ]) ) } @@ -26,11 +26,11 @@ export function getOpenCodeCommandDirs(options: OpenCodeConfigDirOptions): strin export function getOpenCodeSkillDirs(options: OpenCodeConfigDirOptions): string[] { const configDir = getOpenCodeConfigDir(options) const parentConfigDir = getParentOpencodeConfigDir(configDir) - return Array.from( new Set([ join(configDir, "skills"), - ...(parentConfigDir ? [join(parentConfigDir, "skills")] : []), + join(configDir, "skill"), + ...(parentConfigDir ? [join(parentConfigDir, "skills"), join(parentConfigDir, "skill")] : []), ]) ) } diff --git a/src/shared/opencode-config-dir.test.ts b/src/shared/opencode-config-dir.test.ts index 86d3afc55..5d6cf3ef5 100644 --- a/src/shared/opencode-config-dir.test.ts +++ b/src/shared/opencode-config-dir.test.ts @@ -1,6 +1,6 @@ import { describe, test, expect, beforeEach, afterEach } from "bun:test" import { homedir } from "node:os" -import { join, resolve } from "node:path" +import { join, resolve, win32 } from "node:path" import { getOpenCodeConfigDir, getOpenCodeConfigPaths, @@ -241,9 +241,10 @@ describe("opencode-config-dir", () => { // when getOpenCodeConfigDir is called with binary="opencode-desktop" const result = getOpenCodeConfigDir({ binary: "opencode-desktop", version: "1.0.200", checkExisting: false }) - // then returns %APPDATA%/ai.opencode.desktop - expect(result).toBe(join("C:\\Users\\TestUser\\AppData\\Roaming", TAURI_APP_IDENTIFIER)) + // then returns %APPDATA%/ai.opencode.desktop using Windows path semantics + expect(result).toBe(win32.join("C:\\Users\\TestUser\\AppData\\Roaming", TAURI_APP_IDENTIFIER)) }) + }) describe("dev build detection", () => { diff --git a/src/shared/opencode-config-dir.ts b/src/shared/opencode-config-dir.ts index 620d561dd..e1dedc401 100644 --- a/src/shared/opencode-config-dir.ts +++ b/src/shared/opencode-config-dir.ts @@ -1,6 +1,6 @@ -import { existsSync } from "node:fs" +import { existsSync, realpathSync } from "node:fs" import { homedir } from "node:os" -import { join, resolve } from "node:path" +import { join, resolve, win32 } from "node:path" import type { OpenCodeBinaryType, @@ -31,7 +31,7 @@ function getTauriConfigDir(identifier: string): string { case "win32": { const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming") - return join(appData, identifier) + return win32.join(appData, identifier) } case "linux": @@ -42,14 +42,25 @@ function getTauriConfigDir(identifier: string): string { } } +function resolveConfigPath(pathValue: string): string { + const resolvedPath = resolve(pathValue) + if (!existsSync(resolvedPath)) return resolvedPath + + try { + return realpathSync(resolvedPath) + } catch { + return resolvedPath + } +} + function getCliConfigDir(): string { const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim() if (envConfigDir) { - return resolve(envConfigDir) + return resolveConfigPath(envConfigDir) } const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config") - return join(xdgConfig, "opencode") + return resolveConfigPath(join(xdgConfig, "opencode")) } export function getOpenCodeConfigDir(options: OpenCodeConfigDirOptions): string { @@ -60,7 +71,10 @@ export function getOpenCodeConfigDir(options: OpenCodeConfigDirOptions): string } const identifier = isDevBuild(version) ? TAURI_APP_IDENTIFIER_DEV : TAURI_APP_IDENTIFIER - const tauriDir = getTauriConfigDir(identifier) + const tauriDirBase = getTauriConfigDir(identifier) + const tauriDir = process.platform === "win32" + ? (win32.isAbsolute(tauriDirBase) ? win32.normalize(tauriDirBase) : win32.resolve(tauriDirBase)) + : resolveConfigPath(tauriDirBase) if (checkExisting) { const legacyDir = getCliConfigDir() @@ -92,7 +106,7 @@ export function detectExistingConfigDir(binary: OpenCodeBinaryType, version?: st const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim() if (envConfigDir) { - locations.push(resolve(envConfigDir)) + locations.push(resolveConfigPath(envConfigDir)) } if (binary === "opencode-desktop") { diff --git a/src/shared/plugin-config-detection.test.ts b/src/shared/plugin-config-detection.test.ts new file mode 100644 index 000000000..34ad9b434 --- /dev/null +++ b/src/shared/plugin-config-detection.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from "bun:test" +import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs" +import { join } from "node:path" +import { detectPluginConfigFile } from "./jsonc-parser" + +describe("detectPluginConfigFile - canonical config detection", () => { + const testDir = join(__dirname, ".test-detect-plugin-canonical") + + test("detects oh-my-openagent config when no legacy config exists", () => { + //#given + if (!existsSync(testDir)) mkdirSync(testDir, { recursive: true }) + writeFileSync(join(testDir, "oh-my-openagent.jsonc"), "{}") + + //#when + const result = detectPluginConfigFile(testDir) + + //#then + expect(result.format).toBe("jsonc") + expect(result.path).toBe(join(testDir, "oh-my-openagent.jsonc")) + + rmSync(testDir, { recursive: true, force: true }) + }) +}) diff --git a/src/shared/plugin-identity.test.ts b/src/shared/plugin-identity.test.ts index b3bd87cba..6de3c7bdb 100644 --- a/src/shared/plugin-identity.test.ts +++ b/src/shared/plugin-identity.test.ts @@ -3,24 +3,24 @@ import { PLUGIN_NAME, CONFIG_BASENAME, LOG_FILENAME, CACHE_DIR_NAME } from "./pl describe("plugin-identity constants", () => { describe("PLUGIN_NAME", () => { - it("equals oh-my-opencode", () => { + it("equals oh-my-openagent", () => { // given // when // then - expect(PLUGIN_NAME).toBe("oh-my-opencode") + expect(PLUGIN_NAME).toBe("oh-my-openagent") }) }) describe("CONFIG_BASENAME", () => { - it("equals oh-my-opencode", () => { + it("equals oh-my-openagent", () => { // given // when // then - expect(CONFIG_BASENAME).toBe("oh-my-opencode") + expect(CONFIG_BASENAME).toBe("oh-my-openagent") }) }) diff --git a/src/shared/plugin-identity.ts b/src/shared/plugin-identity.ts index 3de14c328..4150283b2 100644 --- a/src/shared/plugin-identity.ts +++ b/src/shared/plugin-identity.ts @@ -1,5 +1,6 @@ -export const PLUGIN_NAME = "oh-my-opencode" -export const LEGACY_PLUGIN_NAME = "oh-my-openagent" -export const CONFIG_BASENAME = "oh-my-opencode" +export const PLUGIN_NAME = "oh-my-openagent" +export const LEGACY_PLUGIN_NAME = "oh-my-opencode" +export const CONFIG_BASENAME = "oh-my-openagent" +export const LEGACY_CONFIG_BASENAME = "oh-my-opencode" export const LOG_FILENAME = "oh-my-opencode.log" export const CACHE_DIR_NAME = "oh-my-opencode" diff --git a/src/shared/project-discovery-dirs.test.ts b/src/shared/project-discovery-dirs.test.ts new file mode 100644 index 000000000..39ba5dc13 --- /dev/null +++ b/src/shared/project-discovery-dirs.test.ts @@ -0,0 +1,92 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdirSync, realpathSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { + findProjectAgentsSkillDirs, + findProjectClaudeSkillDirs, + findProjectOpencodeCommandDirs, + findProjectOpencodeSkillDirs, +} from "./project-discovery-dirs" + +const TEST_DIR = join(tmpdir(), `project-discovery-dirs-${Date.now()}`) + +function canonicalPath(path: string): string { + return realpathSync(path) +} + +describe("project-discovery-dirs", () => { + beforeEach(() => { + mkdirSync(TEST_DIR, { recursive: true }) + }) + + afterEach(() => { + rmSync(TEST_DIR, { recursive: true, force: true }) + }) + + it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", () => { + // given + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "apps", "cli") + mkdirSync(join(projectDir, ".opencode", "skill"), { recursive: true }) + mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) + mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) + + // when + const directories = findProjectOpencodeSkillDirs(childDir) + + // then + expect(directories).toEqual([ + canonicalPath(join(projectDir, ".opencode", "skills")), + canonicalPath(join(projectDir, ".opencode", "skill")), + canonicalPath(join(TEST_DIR, ".opencode", "skills")), + ]) + }) + + it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", () => { + // given + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "packages", "tool") + mkdirSync(join(projectDir, ".opencode", "commands"), { recursive: true }) + mkdirSync(join(TEST_DIR, ".opencode", "command"), { recursive: true }) + + // when + const directories = findProjectOpencodeCommandDirs(childDir) + + // then + expect(directories).toEqual([ + canonicalPath(join(projectDir, ".opencode", "commands")), + canonicalPath(join(TEST_DIR, ".opencode", "command")), + ]) + }) + + it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", () => { + // given + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "src", "nested") + mkdirSync(join(projectDir, ".claude", "skills"), { recursive: true }) + mkdirSync(join(TEST_DIR, ".agents", "skills"), { recursive: true }) + + // when + const claudeDirectories = findProjectClaudeSkillDirs(childDir) + const agentsDirectories = findProjectAgentsSkillDirs(childDir) + + // then + expect(claudeDirectories).toEqual([canonicalPath(join(projectDir, ".claude", "skills"))]) + expect(agentsDirectories).toEqual([canonicalPath(join(TEST_DIR, ".agents", "skills"))]) + }) + + it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", () => { + // given + const projectDir = join(TEST_DIR, "project") + const childDir = join(projectDir, "apps", "cli") + mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) + mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) + + // when + const directories = findProjectOpencodeSkillDirs(childDir, projectDir) + + // then + expect(directories).toEqual([canonicalPath(join(projectDir, ".opencode", "skills"))]) + }) +}) diff --git a/src/shared/project-discovery-dirs.ts b/src/shared/project-discovery-dirs.ts new file mode 100644 index 000000000..4e22b66f6 --- /dev/null +++ b/src/shared/project-discovery-dirs.ts @@ -0,0 +1,101 @@ +import { execFileSync } from "node:child_process" +import { existsSync, realpathSync } from "node:fs" +import { dirname, join, resolve } from "node:path" + +function normalizePath(path: string): string { + const resolvedPath = resolve(path) + if (!existsSync(resolvedPath)) { + return resolvedPath + } + + try { + return realpathSync(resolvedPath) + } catch { + return resolvedPath + } +} + +function findAncestorDirectories( + startDirectory: string, + targetPaths: ReadonlyArray>, + stopDirectory?: string, +): string[] { + const directories: string[] = [] + const seen = new Set() + let currentDirectory = normalizePath(startDirectory) + const resolvedStopDirectory = stopDirectory ? normalizePath(stopDirectory) : undefined + + while (true) { + for (const targetPath of targetPaths) { + const candidateDirectory = join(currentDirectory, ...targetPath) + if (!existsSync(candidateDirectory) || seen.has(candidateDirectory)) { + continue + } + + seen.add(candidateDirectory) + directories.push(candidateDirectory) + } + + if (resolvedStopDirectory === currentDirectory) { + return directories + } + + const parentDirectory = dirname(currentDirectory) + if (parentDirectory === currentDirectory) { + return directories + } + + currentDirectory = normalizePath(parentDirectory) + } +} + +function detectWorktreePath(directory: string): string | undefined { + try { + return execFileSync("git", ["rev-parse", "--show-toplevel"], { + cwd: directory, + encoding: "utf-8", + timeout: 5000, + stdio: ["pipe", "pipe", "pipe"], + }).trim() + } catch { + return undefined + } +} + +export function findProjectClaudeSkillDirs(startDirectory: string, stopDirectory?: string): string[] { + return findAncestorDirectories( + startDirectory, + [[".claude", "skills"]], + stopDirectory ?? detectWorktreePath(startDirectory), + ) +} + +export function findProjectAgentsSkillDirs(startDirectory: string, stopDirectory?: string): string[] { + return findAncestorDirectories( + startDirectory, + [[".agents", "skills"]], + stopDirectory ?? detectWorktreePath(startDirectory), + ) +} + +export function findProjectOpencodeSkillDirs(startDirectory: string, stopDirectory?: string): string[] { + return findAncestorDirectories( + startDirectory, + [ + [".opencode", "skills"], + [".opencode", "skill"], + ], + stopDirectory ?? detectWorktreePath(startDirectory), + ) +} + +export function findProjectOpencodeCommandDirs(startDirectory: string, stopDirectory?: string): string[] { + return findAncestorDirectories( + startDirectory, + [ + [".opencode", "commands"], + [".opencode", "command"], + ], + stopDirectory ?? detectWorktreePath(startDirectory), + ) +} diff --git a/src/tools/delegate-task/category-resolver.ts b/src/tools/delegate-task/category-resolver.ts index 648fa933c..8406652f1 100644 --- a/src/tools/delegate-task/category-resolver.ts +++ b/src/tools/delegate-task/category-resolver.ts @@ -239,6 +239,7 @@ Available categories: ${categoryNames.join(", ")}`, modelInfo, actualModel, isUnstableAgent, - fallbackChain: configuredFallbackChain ?? requirement?.fallbackChain, + // Don't use hardcoded fallback chain when resolution was skipped (cold cache) + fallbackChain: configuredFallbackChain ?? (isModelResolutionSkipped ? undefined : requirement?.fallbackChain), } } diff --git a/src/tools/delegate-task/subagent-resolver.ts b/src/tools/delegate-task/subagent-resolver.ts index fe80af663..df6fe7378 100644 --- a/src/tools/delegate-task/subagent-resolver.ts +++ b/src/tools/delegate-task/subagent-resolver.ts @@ -125,12 +125,26 @@ Create the work plan directly - that's your job as the planning agent.`, systemDefaultModel: undefined, }) - if (resolution && !('skipped' in resolution)) { + const resolutionSkipped = resolution && 'skipped' in resolution + + if (resolution && !resolutionSkipped) { const normalized = normalizeModelFormat(resolution.model) if (normalized) { const variantToUse = agentOverride?.variant ?? resolution.variant categoryModel = variantToUse ? { ...normalized, variant: variantToUse } : normalized } + } else if (resolutionSkipped && agentOverride?.model) { + // Cold cache: resolution was skipped but user explicitly configured a model. + // Honor the user override directly — don't fall through to hardcoded fallback chain. + const normalized = normalizeModelFormat(agentOverride.model) + if (normalized) { + const variantToUse = agentOverride?.variant + categoryModel = variantToUse ? { ...normalized, variant: variantToUse } : normalized + log("[delegate-task] Cold cache: using explicit user override for subagent", { + agent: agentToUse, + model: agentOverride.model, + }) + } } const defaultProviderID = categoryModel?.providerID @@ -140,7 +154,9 @@ Create the work plan directly - that's your job as the planning agent.`, normalizedAgentFallbackModels, defaultProviderID, ) - fallbackChain = configuredFallbackChain ?? agentRequirement?.fallbackChain + // Don't assign hardcoded fallback chain when resolution was skipped (cold cache) + // — the chain may contain model IDs that don't exist in the provider yet. + fallbackChain = configuredFallbackChain ?? (resolutionSkipped ? undefined : agentRequirement?.fallbackChain) // Only promote fallback-only settings when resolution actually selected a fallback model. const resolvedFallbackEntry = (resolution && !('skipped' in resolution)) ? resolution.fallbackEntry : undefined diff --git a/src/tools/look-at/image-converter.test.ts b/src/tools/look-at/image-converter.test.ts index 8acab97b6..12efaacc3 100644 --- a/src/tools/look-at/image-converter.test.ts +++ b/src/tools/look-at/image-converter.test.ts @@ -1,22 +1,14 @@ -import { describe, expect, test, mock, beforeEach } from "bun:test" +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test" +import * as childProcess from "node:child_process" import { existsSync, mkdtempSync, writeFileSync, unlinkSync, rmSync } from "node:fs" import { tmpdir } from "node:os" import { dirname, join } from "node:path" -const originalChildProcess = await import("node:child_process") +type ImageConverterModule = typeof import("./image-converter") -const execFileSyncMock = mock((_command: string, _args: string[], _options?: unknown) => "") -const execSyncMock = mock(() => { - throw new Error("execSync should not be called") -}) - -mock.module("node:child_process", () => ({ - ...originalChildProcess, - execFileSync: execFileSyncMock, - execSync: execSyncMock, -})) - -const { convertImageToJpeg, cleanupConvertedImage } = await import("./image-converter") +async function loadImageConverter(): Promise { + return import(`./image-converter?test=${Date.now()}-${Math.random()}`) +} function writeConvertedOutput(command: string, args: string[]): void { if (command === "sips") { @@ -38,7 +30,10 @@ function writeConvertedOutput(command: string, args: string[]): void { } } -function withMockPlatform(platform: NodeJS.Platform, run: () => TValue): TValue { +async function withMockPlatform( + platform: NodeJS.Platform, + run: () => TValue | Promise, +): Promise { const originalPlatform = process.platform Object.defineProperty(process, "platform", { value: platform, @@ -46,7 +41,7 @@ function withMockPlatform(platform: NodeJS.Platform, run: () => TValue): }) try { - return run() + return await run() } finally { Object.defineProperty(process, "platform", { value: originalPlatform, @@ -56,34 +51,50 @@ function withMockPlatform(platform: NodeJS.Platform, run: () => TValue): } describe("image-converter command execution safety", () => { + let execFileSyncSpy: ReturnType + let execSyncSpy: ReturnType + beforeEach(() => { - execFileSyncMock.mockReset() - execSyncMock.mockReset() + execSyncSpy = spyOn(childProcess, "execSync").mockImplementation(() => { + throw new Error("execSync should not be called") + }) + + execFileSyncSpy = spyOn(childProcess, "execFileSync").mockImplementation( + ((_command: string, _args: string[], _options?: unknown) => "") as typeof childProcess.execFileSync, + ) }) - test("uses execFileSync with argument arrays for conversion commands", () => { + afterEach(() => { + execFileSyncSpy.mockRestore() + execSyncSpy.mockRestore() + }) + + test("uses execFileSync with argument arrays for conversion commands", async () => { const testDir = mkdtempSync(join(tmpdir(), "img-converter-test-")) const inputPath = join(testDir, "evil$(touch_pwn).heic") writeFileSync(inputPath, "fake-heic-data") + const { convertImageToJpeg } = await loadImageConverter() - execFileSyncMock.mockImplementation((command: string, args: string[]) => { - writeConvertedOutput(command, args) - return "" - }) + execFileSyncSpy.mockImplementation( + ((command: string, args: string[]) => { + writeConvertedOutput(command, args) + return "" + }) as typeof childProcess.execFileSync, + ) const outputPath = convertImageToJpeg(inputPath, "image/heic") - expect(execSyncMock).not.toHaveBeenCalled() - expect(execFileSyncMock).toHaveBeenCalled() + expect(execSyncSpy).not.toHaveBeenCalled() + expect(execFileSyncSpy).toHaveBeenCalled() - const [firstCommand, firstArgs] = execFileSyncMock.mock.calls[0] as [string, string[]] + const [firstCommand, firstArgs] = execFileSyncSpy.mock.calls[0] as [string, string[]] expect(typeof firstCommand).toBe("string") expect(Array.isArray(firstArgs)).toBe(true) expect(["sips", "convert", "magick"]).toContain(firstCommand) expect(firstArgs).toContain("--") expect(firstArgs).toContain(inputPath) expect(firstArgs.indexOf("--") < firstArgs.indexOf(inputPath)).toBe(true) - expect(firstArgs.join(" ")).not.toContain(`\"${inputPath}\"`) + expect(firstArgs.join(" ")).not.toContain(`"${inputPath}"`) expect(existsSync(outputPath)).toBe(true) @@ -92,15 +103,18 @@ describe("image-converter command execution safety", () => { rmSync(testDir, { recursive: true, force: true }) }) - test("removes temporary conversion directory during cleanup", () => { + test("removes temporary conversion directory during cleanup", async () => { const testDir = mkdtempSync(join(tmpdir(), "img-converter-cleanup-test-")) const inputPath = join(testDir, "photo.heic") writeFileSync(inputPath, "fake-heic-data") + const { convertImageToJpeg, cleanupConvertedImage } = await loadImageConverter() - execFileSyncMock.mockImplementation((command: string, args: string[]) => { - writeConvertedOutput(command, args) - return "" - }) + execFileSyncSpy.mockImplementation( + ((command: string, args: string[]) => { + writeConvertedOutput(command, args) + return "" + }) as typeof childProcess.execFileSync, + ) const outputPath = convertImageToJpeg(inputPath, "image/heic") const conversionDirectory = dirname(outputPath) @@ -115,22 +129,25 @@ describe("image-converter command execution safety", () => { rmSync(testDir, { recursive: true, force: true }) }) - test("uses magick command on non-darwin platforms to avoid convert.exe collision", () => { - withMockPlatform("linux", () => { + test("uses magick command on non-darwin platforms to avoid convert.exe collision", async () => { + await withMockPlatform("linux", async () => { const testDir = mkdtempSync(join(tmpdir(), "img-converter-platform-test-")) const inputPath = join(testDir, "photo.heic") writeFileSync(inputPath, "fake-heic-data") + const { convertImageToJpeg, cleanupConvertedImage } = await loadImageConverter() - execFileSyncMock.mockImplementation((command: string, args: string[]) => { - if (command === "magick") { - writeFileSync(args[2], "jpeg") - } - return "" - }) + execFileSyncSpy.mockImplementation( + ((command: string, args: string[]) => { + if (command === "magick") { + writeFileSync(args[2], "jpeg") + } + return "" + }) as typeof childProcess.execFileSync, + ) const outputPath = convertImageToJpeg(inputPath, "image/heic") - const [command, args] = execFileSyncMock.mock.calls[0] as [string, string[]] + const [command, args] = execFileSyncSpy.mock.calls[0] as [string, string[]] expect(command).toBe("magick") expect(args).toContain("--") expect(args.indexOf("--") < args.indexOf(inputPath)).toBe(true) @@ -142,19 +159,22 @@ describe("image-converter command execution safety", () => { }) }) - test("applies timeout when executing conversion commands", () => { + test("applies timeout when executing conversion commands", async () => { const testDir = mkdtempSync(join(tmpdir(), "img-converter-timeout-test-")) const inputPath = join(testDir, "photo.heic") writeFileSync(inputPath, "fake-heic-data") + const { convertImageToJpeg, cleanupConvertedImage } = await loadImageConverter() - execFileSyncMock.mockImplementation((command: string, args: string[]) => { - writeConvertedOutput(command, args) - return "" - }) + execFileSyncSpy.mockImplementation( + ((command: string, args: string[]) => { + writeConvertedOutput(command, args) + return "" + }) as typeof childProcess.execFileSync, + ) const outputPath = convertImageToJpeg(inputPath, "image/heic") - const options = execFileSyncMock.mock.calls[0]?.[2] as { timeout?: number } | undefined + const options = execFileSyncSpy.mock.calls[0]?.[2] as { timeout?: number } | undefined expect(options).toBeDefined() expect(typeof options?.timeout).toBe("number") expect((options?.timeout ?? 0) > 0).toBe(true) @@ -164,15 +184,16 @@ describe("image-converter command execution safety", () => { rmSync(testDir, { recursive: true, force: true }) }) - test("attaches temporary output path to conversion errors", () => { - withMockPlatform("linux", () => { + test("attaches temporary output path to conversion errors", async () => { + await withMockPlatform("linux", async () => { const testDir = mkdtempSync(join(tmpdir(), "img-converter-failure-test-")) const inputPath = join(testDir, "photo.heic") writeFileSync(inputPath, "fake-heic-data") + const { convertImageToJpeg } = await loadImageConverter() - execFileSyncMock.mockImplementation(() => { + execFileSyncSpy.mockImplementation((() => { throw new Error("conversion process failed") - }) + }) as typeof childProcess.execFileSync) const runConversion = () => convertImageToJpeg(inputPath, "image/heic") expect(runConversion).toThrow("No image conversion tool available") diff --git a/src/tools/look-at/image-converter.ts b/src/tools/look-at/image-converter.ts index fe3b6be05..163e35e28 100644 --- a/src/tools/look-at/image-converter.ts +++ b/src/tools/look-at/image-converter.ts @@ -1,4 +1,4 @@ -import { execFileSync } from "node:child_process" +import * as childProcess from "node:child_process" import { existsSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { dirname, join } from "node:path" @@ -59,7 +59,7 @@ export function convertImageToJpeg(inputPath: string, mimeType: string): string try { if (process.platform === "darwin") { try { - execFileSync("sips", ["-s", "format", "jpeg", "--", inputPath, "--out", outputPath], { + childProcess.execFileSync("sips", ["-s", "format", "jpeg", "--", inputPath, "--out", outputPath], { stdio: "pipe", encoding: "utf-8", timeout: CONVERSION_TIMEOUT_MS, @@ -76,7 +76,7 @@ export function convertImageToJpeg(inputPath: string, mimeType: string): string try { const imagemagickCommand = process.platform === "darwin" ? "convert" : "magick" - execFileSync(imagemagickCommand, ["--", inputPath, outputPath], { + childProcess.execFileSync(imagemagickCommand, ["--", inputPath, outputPath], { stdio: "pipe", encoding: "utf-8", timeout: CONVERSION_TIMEOUT_MS, diff --git a/src/tools/slashcommand/command-discovery.test.ts b/src/tools/slashcommand/command-discovery.test.ts index 36e59ba0c..b0b3c2b5a 100644 --- a/src/tools/slashcommand/command-discovery.test.ts +++ b/src/tools/slashcommand/command-discovery.test.ts @@ -181,4 +181,78 @@ Use parent opencode commit command. expect(commitCommand?.scope).toBe("opencode") expect(commitCommand?.content).toContain("Use parent opencode commit command.") }) + + it("discovers ancestor project opencode commands from plural commands directory", () => { + const projectRoot = join(projectDir, "workspace") + const childDir = join(projectRoot, "apps", "cli") + const commandsDir = join(projectRoot, ".opencode", "commands") + + mkdirSync(childDir, { recursive: true }) + mkdirSync(commandsDir, { recursive: true }) + writeFileSync( + join(commandsDir, "ancestor.md"), + `--- +description: Discover command from ancestor plural directory +--- +Use ancestor command. +`, + ) + + const commands = discoverCommandsSync(childDir) + const ancestorCommand = commands.find((command) => command.name === "ancestor") + + expect(ancestorCommand?.scope).toBe("opencode-project") + expect(ancestorCommand?.content).toContain("Use ancestor command.") + }) + + it("deduplicates same-named opencode commands while keeping the higher-priority alias", () => { + const commandsRoot = join(projectDir, ".opencode") + const singularDir = join(commandsRoot, "command") + const pluralDir = join(commandsRoot, "commands") + + mkdirSync(singularDir, { recursive: true }) + mkdirSync(pluralDir, { recursive: true }) + writeFileSync( + join(singularDir, "duplicate.md"), + `--- +description: Singular duplicate command +--- +Use singular command. +`, + ) + writeFileSync( + join(pluralDir, "duplicate.md"), + `--- +description: Plural duplicate command +--- +Use plural command. +`, + ) + + const commands = discoverCommandsSync(projectDir) + const duplicates = commands.filter((command) => command.name === "duplicate") + + expect(duplicates).toHaveLength(1) + expect(duplicates[0]?.content).toContain("Use plural command.") + }) + + it("discovers nested opencode project commands", () => { + const commandsDir = join(projectDir, ".opencode", "commands", "refactor") + + mkdirSync(commandsDir, { recursive: true }) + writeFileSync( + join(commandsDir, "code.md"), + `--- +description: Nested command +--- +Use nested command. +`, + ) + + const commands = discoverCommandsSync(projectDir) + const nestedCommand = commands.find((command) => command.name === "refactor/code") + + expect(nestedCommand?.content).toContain("Use nested command.") + expect(nestedCommand?.scope).toBe("opencode-project") + }) }) diff --git a/src/tools/slashcommand/command-discovery.ts b/src/tools/slashcommand/command-discovery.ts index 7fb96c322..dc8922381 100644 --- a/src/tools/slashcommand/command-discovery.ts +++ b/src/tools/slashcommand/command-discovery.ts @@ -3,6 +3,7 @@ import { basename, join } from "path" import { parseFrontmatter, sanitizeModelField, + findProjectOpencodeCommandDirs, getOpenCodeCommandDirs, discoverPluginCommandDefinitions, } from "../../shared" @@ -17,17 +18,37 @@ export interface CommandDiscoveryOptions { enabledPluginsOverride?: Record } -function discoverCommandsFromDir(commandsDir: string, scope: CommandScope): CommandInfo[] { +const NESTED_COMMAND_SEPARATOR = "/" + +function discoverCommandsFromDir( + commandsDir: string, + scope: CommandScope, + prefix = "", +): CommandInfo[] { if (!existsSync(commandsDir)) return [] const entries = readdirSync(commandsDir, { withFileTypes: true }) const commands: CommandInfo[] = [] for (const entry of entries) { + if (entry.isDirectory()) { + if (entry.name.startsWith(".")) continue + const nestedPrefix = prefix + ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` + : entry.name + commands.push( + ...discoverCommandsFromDir(join(commandsDir, entry.name), scope, nestedPrefix), + ) + continue + } + if (!isMarkdownFile(entry)) continue const commandPath = join(commandsDir, entry.name) - const commandName = basename(entry.name, ".md") + const baseCommandName = basename(entry.name, ".md") + const commandName = prefix + ? `${prefix}${NESTED_COMMAND_SEPARATOR}${baseCommandName}` + : baseCommandName try { const content = readFileSync(commandPath, "utf-8") @@ -75,6 +96,22 @@ function discoverPluginCommands(options?: CommandDiscoveryOptions): CommandInfo[ })) } +function deduplicateCommandInfosByName(commands: CommandInfo[]): CommandInfo[] { + const seen = new Set() + const deduplicatedCommands: CommandInfo[] = [] + + for (const command of commands) { + if (seen.has(command.name)) { + continue + } + + seen.add(command.name) + deduplicatedCommands.push(command) + } + + return deduplicatedCommands +} + export function discoverCommandsSync( directory?: string, options?: CommandDiscoveryOptions, @@ -82,14 +119,16 @@ export function discoverCommandsSync( const userCommandsDir = join(getClaudeConfigDir(), "commands") const projectCommandsDir = join(directory ?? process.cwd(), ".claude", "commands") const opencodeGlobalDirs = getOpenCodeCommandDirs({ binary: "opencode" }) - const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "command") + const opencodeProjectDirs = findProjectOpencodeCommandDirs(directory ?? process.cwd()) const userCommands = discoverCommandsFromDir(userCommandsDir, "user") const opencodeGlobalCommands = opencodeGlobalDirs.flatMap((commandsDir) => discoverCommandsFromDir(commandsDir, "opencode") ) const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project") - const opencodeProjectCommands = discoverCommandsFromDir(opencodeProjectDir, "opencode-project") + const opencodeProjectCommands = opencodeProjectDirs.flatMap((commandsDir) => + discoverCommandsFromDir(commandsDir, "opencode-project"), + ) const pluginCommands = discoverPluginCommands(options) const builtinCommandsMap = loadBuiltinCommands() @@ -107,12 +146,12 @@ export function discoverCommandsSync( scope: "builtin", })) - return [ + return deduplicateCommandInfosByName([ ...projectCommands, ...userCommands, ...opencodeProjectCommands, ...opencodeGlobalCommands, ...builtinCommands, ...pluginCommands, - ] + ]) } diff --git a/src/tools/slashcommand/opencode-project-command-discovery.test.ts b/src/tools/slashcommand/opencode-project-command-discovery.test.ts new file mode 100644 index 000000000..3192564bd --- /dev/null +++ b/src/tools/slashcommand/opencode-project-command-discovery.test.ts @@ -0,0 +1,62 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { discoverCommandsSync } from "./command-discovery" + +function writeCommand(path: string, description: string, body: string): void { + mkdirSync(join(path, ".."), { recursive: true }) + writeFileSync(path, `---\ndescription: ${description}\n---\n${body}\n`) +} + +describe("opencode project command discovery", () => { + let tempDir = "" + + beforeEach(() => { + tempDir = mkdtempSync(join(tmpdir(), "omo-opencode-project-command-discovery-")) + }) + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }) + }) + + it("discovers ancestor opencode commands with slash-separated nested names and worktree boundaries", () => { + // given + const repositoryDir = join(tempDir, "repo") + const nestedDirectory = join(repositoryDir, "packages", "app", "src") + + mkdirSync(nestedDirectory, { recursive: true }) + // Use Bun.spawnSync instead of execFileSync to avoid mock leakage + // from parallel test files (e.g. image-converter.test.ts mocks execFileSync globally) + Bun.spawnSync(["git", "init"], { + cwd: repositoryDir, + stdout: "ignore", + stderr: "ignore", + }) + + writeCommand( + join(repositoryDir, ".opencode", "commands", "deploy", "staging.md"), + "Deploy to staging", + "Run the staged deploy.", + ) + writeCommand( + join(repositoryDir, ".opencode", "command", "release.md"), + "Release command", + "Run the release.", + ) + writeCommand( + join(tempDir, ".opencode", "commands", "outside.md"), + "Outside command", + "Should not be discovered.", + ) + + // when + const names = discoverCommandsSync(nestedDirectory).map(command => command.name) + + // then + expect(names).toContain("deploy/staging") + expect(names).toContain("release") + expect(names).not.toContain("deploy:staging") + expect(names).not.toContain("outside") + }) +}) diff --git a/src/tools/task/todo-sync.test.ts b/src/tools/task/todo-sync.test.ts index e35d1978b..d6c87c3df 100644 --- a/src/tools/task/todo-sync.test.ts +++ b/src/tools/task/todo-sync.test.ts @@ -27,7 +27,7 @@ describe("syncTaskToTodo", () => { id: "T-123", content: "Fix bug", status: "pending", - priority: undefined, + priority: "medium", }); }); @@ -159,7 +159,7 @@ describe("syncTaskToTodo", () => { const result = syncTaskToTodo(task); // then - expect(result?.priority).toBeUndefined(); + expect(result?.priority).toBe("medium"); }); it("handles missing metadata", () => { @@ -177,7 +177,7 @@ describe("syncTaskToTodo", () => { const result = syncTaskToTodo(task); // then - expect(result?.priority).toBeUndefined(); + expect(result?.priority).toBe("medium"); }); it("uses subject as todo content", () => { diff --git a/test-setup.ts b/test-setup.ts index 5ac63e4e6..5c6e5aa0d 100644 --- a/test-setup.ts +++ b/test-setup.ts @@ -1,6 +1,8 @@ import { beforeEach } from "bun:test" -import { _resetForTesting } from "./src/features/claude-code-session-state/state" +import { _resetForTesting as resetClaudeSessionState } from "./src/features/claude-code-session-state/state" +import { _resetForTesting as resetModelFallbackState } from "./src/hooks/model-fallback/hook" beforeEach(() => { - _resetForTesting() + resetClaudeSessionState() + resetModelFallbackState() })