diff --git a/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt b/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt new file mode 100644 index 000000000..d3f55481c --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-category-prompt-required.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 1 expect() calls +Ran 1 test across 1 file. [64.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-disc-both.txt b/.sisyphus/evidence/team-mode/task-2-disc-both.txt new file mode 100644 index 000000000..1174095e7 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-disc-both.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 1 expect() calls +Ran 1 test across 1 file. [65.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-disc-category.txt b/.sisyphus/evidence/team-mode/task-2-disc-category.txt new file mode 100644 index 000000000..7aed175f2 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-disc-category.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 3 expect() calls +Ran 1 test across 1 file. [69.00ms] diff --git a/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt b/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt new file mode 100644 index 000000000..749f3d548 --- /dev/null +++ b/.sisyphus/evidence/team-mode/task-2-eligibility-registry.txt @@ -0,0 +1,7 @@ +bun test v1.3.12 (700fc117) + + 1 pass + 3 filtered out + 0 fail + 12 expect() calls +Ran 1 test across 1 file. [61.00ms] diff --git a/.sisyphus/notepads/team-mode/learnings.md b/.sisyphus/notepads/team-mode/learnings.md new file mode 100644 index 000000000..97e13ba01 --- /dev/null +++ b/.sisyphus/notepads/team-mode/learnings.md @@ -0,0 +1,10 @@ +## 2026-04-18 Task 2: types module + +- `MemberSchema` needs `.strict()` on the base shape so the discriminatedUnion rejects members that mix `category` and `subagent_type`. +- `backendType` and `isActive` defaults are part of the schema contract, so tests should use `toMatchObject` instead of exact object equality. +- The eligibility registry must preserve the plan strings verbatim, especially the hard-reject messages for Momus verification. +## Task 12 learnings + +- `git worktree remove` can leave prunable entries behind, so pruning after removal keeps the repo index tidy. +- For testability, a tiny git command runner hook made git-unavailable coverage simpler than mocking Bun directly. +- Detached worktrees need unique temp paths in tests to avoid cross-run collisions. diff --git a/AGENTS.md b/AGENTS.md index 64bed7618..02af070b0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,17 +1,17 @@ # oh-my-opencode — OpenCode Plugin -**Generated:** 2026-04-11 | **Commit:** f5dc1c0e | **Branch:** dev +**Generated:** 2026-04-18 | **Commit:** 2892ca4a | **Branch:** dev ## OVERVIEW -OpenCode plugin (npm: `oh-my-opencode`) extending Claude Code with multi-agent orchestration, 52 lifecycle hooks, 26 tools, skill/command/MCP systems, Hashline edit tool, IntentGate classifier, and Claude Code compatibility. ~1600 TypeScript source files. Dual-published as `oh-my-opencode` + `oh-my-openagent` during transition. +OpenCode plugin (npm: `oh-my-opencode`, dual-published as `oh-my-openagent` during transition) extending Claude Code with 11 agents, 52 lifecycle hooks, 26 tools, 3-tier MCP system (built-in + .mcp.json + skill-embedded), Hashline LINE#ID edit tool, IntentGate classifier, and Claude Code compatibility. 1766 TypeScript source files, 377k LOC, 104 barrel index.ts files. Entry: `src/index.ts` → 5-step init (loadConfig → createManagers → createTools → createHooks → createPluginInterface). ## STRUCTURE ``` oh-my-opencode/ ├── src/ -│ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface +│ ├── index.ts # Plugin entry: default export `pluginModule`, shape `{ id, server }` │ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── hooks/ # 52 lifecycle hooks across dedicated modules and standalone files @@ -33,7 +33,7 @@ oh-my-opencode/ ## INITIALIZATION FLOW ``` -OhMyOpenCodePlugin(ctx) +pluginModule.server(input, options) ├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate ├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler ├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e12993d1b..f1ded421d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,7 +109,7 @@ After making changes, you can test your local build in OpenCode: ``` oh-my-opencode/ ├── src/ -│ ├── index.ts # Plugin entry (OhMyOpenCodePlugin) +│ ├── index.ts # Plugin entry (V1 PluginModule, default export) │ ├── plugin-config.ts # JSONC multi-level config (Zod v4) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── hooks/ # 52 lifecycle hooks across 55 dedicated modules @@ -183,7 +183,7 @@ import type { AgentConfig } from "./types"; export const myAgent: AgentConfig = { name: "my-agent", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", description: "Description of what this agent does", prompt: `Your agent's system prompt here`, temperature: 0.1, diff --git a/README.ja.md b/README.ja.md index af5d32400..a8fe8e1e1 100644 --- a/README.ja.md +++ b/README.ja.md @@ -170,11 +170,11 @@ 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`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 **Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 すべてのエージェントは、それぞれのモデルの強みに合わせてチューニングされています。手動でモデルを切り替える必要はありません。[詳しくはこちら →](docs/guide/overview.md) diff --git a/README.ko.md b/README.ko.md index cf1f60a83..1e3a8294f 100644 --- a/README.ko.md +++ b/README.ko.md @@ -164,11 +164,11 @@ 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`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. **Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. 모든 에이전트는 해당 모델의 특장점에 맞춰 튜닝되어 있습니다. 수동으로 모델 바꿔가며 뻘짓하지 마세요. [더 알아보기 →](docs/guide/overview.md) diff --git a/README.md b/README.md index 8aec143a3..8f7644cc3 100644 --- a/README.md +++ b/README.md @@ -166,11 +166,11 @@ 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. +**Sisyphus** (`claude-opus-4-7` / **`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.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. +**Prometheus** (`claude-opus-4-7` / **`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. Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md) diff --git a/README.ru.md b/README.ru.md index f7564f8b1..65af04c3a 100644 --- a/README.ru.md +++ b/README.ru.md @@ -154,11 +154,11 @@ 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`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. **Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. Каждый агент настроен под сильные стороны своей модели. Никакого ручного переключения между моделями. Подробнее → diff --git a/README.zh-cn.md b/README.zh-cn.md index a3316541c..2d80093bd 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -171,11 +171,11 @@ 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`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 +**Sisyphus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 **Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* -**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 +**Prometheus** (`claude-opus-4-7` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 每一个 Agent 都针对其底层模型的特点进行了专门调优。你无需手动来回切换模型。[阅读背景设定了解更多 →](docs/guide/overview.md) diff --git a/assets/oh-my-opencode.schema.json b/assets/oh-my-opencode.schema.json index 89a60406d..056c84342 100644 --- a/assets/oh-my-opencode.schema.json +++ b/assets/oh-my-opencode.schema.json @@ -5673,11 +5673,6 @@ "minimum": 1, "maximum": 9007199254740991 }, - "maxDescendants": { - "type": "integer", - "minimum": 1, - "maximum": 9007199254740991 - }, "staleTimeoutMs": { "type": "number", "minimum": 60000 diff --git a/bun.lock b/bun.lock index d3c61f010..77c29ca5b 100644 --- a/bun.lock +++ b/bun.lock @@ -21,26 +21,29 @@ "picomatch": "^4.0.2", "posthog-node": "^5.29.2", "vscode-jsonrpc": "^8.2.0", - "zod": "^4.3.0", }, "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/picomatch": "^3.0.2", "bun-types": "1.3.11", "typescript": "^5.7.3", + "zod": "^4.3.0", }, "optionalDependencies": { - "oh-my-opencode-darwin-arm64": "3.17.2", - "oh-my-opencode-darwin-x64": "3.17.2", - "oh-my-opencode-darwin-x64-baseline": "3.17.2", - "oh-my-opencode-linux-arm64": "3.17.2", - "oh-my-opencode-linux-arm64-musl": "3.17.2", - "oh-my-opencode-linux-x64": "3.17.2", - "oh-my-opencode-linux-x64-baseline": "3.17.2", - "oh-my-opencode-linux-x64-musl": "3.17.2", - "oh-my-opencode-linux-x64-musl-baseline": "3.17.2", - "oh-my-opencode-windows-x64": "3.17.2", - "oh-my-opencode-windows-x64-baseline": "3.17.2", + "oh-my-opencode-darwin-arm64": "3.17.4", + "oh-my-opencode-darwin-x64": "3.17.4", + "oh-my-opencode-darwin-x64-baseline": "3.17.4", + "oh-my-opencode-linux-arm64": "3.17.4", + "oh-my-opencode-linux-arm64-musl": "3.17.4", + "oh-my-opencode-linux-x64": "3.17.4", + "oh-my-opencode-linux-x64-baseline": "3.17.4", + "oh-my-opencode-linux-x64-musl": "3.17.4", + "oh-my-opencode-linux-x64-musl-baseline": "3.17.4", + "oh-my-opencode-windows-x64": "3.17.4", + "oh-my-opencode-windows-x64-baseline": "3.17.4", + }, + "peerDependencies": { + "zod": "^4.0.0", }, }, }, @@ -238,27 +241,27 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.2", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-GcEMpe2Q9ocbXtJgcdY1ZnINdpyp+FU6lHeuhqSMaFj9Eba3QTZ7p87PKpV0rwHvQ2q4nyb47Am+JheKVptRhg=="], + "oh-my-opencode-darwin-arm64": ["oh-my-opencode-darwin-arm64@3.17.4", "", { "os": "darwin", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-N135KhfHom/qiP3lgMHfY8DvRNVyOzZMuUs6p6uYTekLduSg3i72Pnc2WyNTZEKFX2yehaLjC5ireY8SnRCbdg=="], - "oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-KEHAOljGrKMWlUWXLfcUiw32nVM2HhcxTYmjtoLdveiLUBEIidokFyCrXHZPU45BKIs1jVVGx4Q3qQrboAx7nA=="], + "oh-my-opencode-darwin-x64": ["oh-my-opencode-darwin-x64@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-LSh5o4oC7ItuIoqd7s1UCAVZ5I7JftEBgeLoatUeto/8by1O6MYvm12ljjP8HIXLsnfi3nJfipqLyXAiiHDHPQ=="], - "oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.2", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BJhPlaQlAVDfGeCPY1fLe0UNVVSdYFq53ZYb61WVvhSgHnvakJGS6wSG+Al69RvAJx5qZ4i76Aw7CZWnLvDVLw=="], + "oh-my-opencode-darwin-x64-baseline": ["oh-my-opencode-darwin-x64-baseline@3.17.4", "", { "os": "darwin", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-caGra13pBdRoV/jCdRWZNeu8XUHUgIxBVn9guAJfT9bZ7AoBurqwO0wgJHUFghOydTdFxPBOGbSOYzJY3Hco5Q=="], - "oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-AYE6gCM9uMbzf83Sja0qBpxvN4JZzOHpY0MbZGEN/zfzgAVF+9Xh0bx2zKDVWA6GHhgtTJKO7xIUal8f9mUgtQ=="], + "oh-my-opencode-linux-arm64": ["oh-my-opencode-linux-arm64@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-P9BAlcybNmJn7ZEq4pKI/qeeP6eUJd0/M/unP+FCjKJE/UwY0YJTYS/Jf9PPZbLCgwbJErPglZe2Ku6t/NXAxQ=="], - "oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.2", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-l4mRpCbx6ccFY1am6hD9qsrJxbwPVelHOplEdSdfvgPWiOIlDXoV5dsiGSOn5TbpjA7a3KNKXmctBK9utmkJwA=="], + "oh-my-opencode-linux-arm64-musl": ["oh-my-opencode-linux-arm64-musl@3.17.4", "", { "os": "linux", "cpu": "arm64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-F7HNYc/DygFsrraMbvXSQjb16NnC9EgtBsbWgHNkRm6UbxVHkWGIuVdHFEUJ1CqHPm2C/9xIuKJ5jiZrtEXqaA=="], - "oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0mqEN73FFAsk+CmvHR/FiOV0AavaNp7CI5c5W/57remxxY4bEfhs2Q+idhv6hbmraEvM/vxoTYMBhExogpo75A=="], + "oh-my-opencode-linux-x64": ["oh-my-opencode-linux-x64@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-WgDiowJBI7nXxqFZDo3FbR0lRkxURrFbBjDVfpqj7jxRQfUrVtwedNjkgxCF8eBOQwoBrijTmxG40GiF4z219g=="], - "oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-hNYG8laRQAS6akx3zKY8YXZ0kObseXjlU5gKe/7z0uAtSMgQhvyXn/uA68gwuU5eXNCDICwTJgxJOcI1vnYIFA=="], + "oh-my-opencode-linux-x64-baseline": ["oh-my-opencode-linux-x64-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-BVJR1qiFe1WykrTBGYmd9XT387yR6VY8jupS/Pu0pqamRYBjeSlER4HQjOcrMY1XHJ/ygsspOcaWKJbSQ8Wcvw=="], - "oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-3tPJ9INHwhAI24Guqi3p7LKbY+zKalQ7vPj5AhTWrWCCt7Lcr7zsTg0Atz2nMVl0UJ8xbBa2jNjn/dmFg1cDng=="], + "oh-my-opencode-linux-x64-musl": ["oh-my-opencode-linux-x64-musl@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-qbLyLSc6bMAys6AwQnD4a3PR9KJNSDaMvA9DA9ARz9+yZ1tb7aA2JdEA24xAoxwct7k2EzxnQI+gssJJM4VUoQ=="], - "oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.2", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-0TvudUyQvAcw6PM4wcZX7NY+xcyOIObJ9+kxYUU8e/saWYKVvkISBowzKDBjFuptbX4gVOvz6JVEfPaiCJxYNA=="], + "oh-my-opencode-linux-x64-musl-baseline": ["oh-my-opencode-linux-x64-musl-baseline@3.17.4", "", { "os": "linux", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode" } }, "sha512-ETqpbPN4HHc0wKfNSeAI2f0NE4nzUq+x85APomPRitVfTPxjdZbQd0TSc0O85vjT+kWj6cXjnHtviHB2BtxHog=="], - "oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-LKr8v+o9KByFUhIvzc6MGLr7/k9hZjHfYnFfcdbiAPCwsIvr8j2RLcl0LhUg1OQD6/U5JikjVYPYGqKanD44QA=="], + "oh-my-opencode-windows-x64": ["oh-my-opencode-windows-x64@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-RC34rbTJGtJeOvp2WTY4ZgVmtkjrduVmXCVMcIdgvQ53yNmNqx79nDITm9FVBA8Id02AHJbYmXGxKvr+XpHbNA=="], - "oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.2", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-zVHptYD3Jzpah2301NAW7eNQ3WgW43cz4mGNrmj0jDpFQVeLy+UwXoGgFuYdZS8kuG9ARYtRA8e5M+0iAWnmbQ=="], + "oh-my-opencode-windows-x64-baseline": ["oh-my-opencode-windows-x64-baseline@3.17.4", "", { "os": "win32", "cpu": "x64", "bin": { "oh-my-opencode": "bin/oh-my-opencode.exe" } }, "sha512-pi43bhDpt6l1fnxkqYYkWCsec1RNxsWL7FZDXoLOGJq/0y3bobWiTNDhbEWNr+uJvOrMs/Sv3qpF1TmYeTvdiA=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], diff --git a/docs/examples/coding-focused.jsonc b/docs/examples/coding-focused.jsonc index 5df5592bc..d697884f8 100644 --- a/docs/examples/coding-focused.jsonc +++ b/docs/examples/coding-focused.jsonc @@ -8,7 +8,7 @@ // Primary orchestrator: aggressive parallel delegation "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.", }, diff --git a/docs/examples/default.jsonc b/docs/examples/default.jsonc index d48f26e7d..160ef1405 100644 --- a/docs/examples/default.jsonc +++ b/docs/examples/default.jsonc @@ -7,8 +7,8 @@ "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" }, + "model": "anthropic/claude-opus-4-7", + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Deep autonomous worker: end-to-end implementation @@ -50,7 +50,7 @@ "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" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "writing": { "model": "google/gemini-3-flash" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" }, "deep": { "model": "openai/gpt-5.4" }, diff --git a/docs/examples/planning-focused.jsonc b/docs/examples/planning-focused.jsonc index 48ab12c1b..407045244 100644 --- a/docs/examples/planning-focused.jsonc +++ b/docs/examples/planning-focused.jsonc @@ -7,8 +7,8 @@ "agents": { // Orchestrator: delegates to planning agents first "sisyphus": { - "model": "anthropic/claude-opus-4-6", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "model": "anthropic/claude-opus-4-7", + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.", }, @@ -20,7 +20,7 @@ // Primary planner: deep interview mode "prometheus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "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.", }, @@ -43,7 +43,7 @@ // Plan review and refinement: heavily utilized "metis": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.", }, @@ -98,7 +98,7 @@ "openai": 3, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "openai/gpt-5.4": 2, }, }, diff --git a/docs/guide/agent-model-matching.md b/docs/guide/agent-model-matching.md index 1d5cc103e..c2115039b 100644 --- a/docs/guide/agent-model-matching.md +++ b/docs/guide/agent-model-matching.md @@ -64,8 +64,8 @@ These agents have Claude-optimized prompts — long, detailed, mechanics-driven. | Agent | Role | Fallback Chain | Notes | | ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | -| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → zai-coding-plan\|opencode\|vercel/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Dual-Prompt Agents → Claude preferred, GPT supported @@ -73,7 +73,7 @@ These agents ship separate prompts for Claude and GPT families. They auto-detect | Agent | Role | Fallback Chain | Notes | | -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- | -| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → opencode-go\|vercel/glm-5 → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Deep Specialists → GPT @@ -83,8 +83,8 @@ These agents are built for GPT's principle-driven style. Their prompts assume au | Agent | Role | Fallback Chain | Notes | | -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ | | **Hephaestus** | Autonomous deep worker | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) | Single-entry chain. Requires one of those providers. The craftsman. | -| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode\|vercel/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → opencode-go\|vercel/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | ### Utility Runners → Speed over Intelligence @@ -92,8 +92,8 @@ These agents do grep, search, and retrieval. They intentionally use the fastest, | Agent | Role | Fallback Chain | Notes | | --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- | -| **Explore** | Fast codebase grep | github-copilot\|xai\|vercel/grok-code-fast-1 → opencode-go\|vercel/minimax-m2.7-highspeed → opencode\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Librarian** | Docs/code search | opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/minimax-m2.7-highspeed → anthropic\|opencode\|vercel/claude-haiku-4-5 → opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Explore** | Fast codebase grep | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Librarian** | Docs/code search | openai/gpt-5.4-mini-fast → opencode-go\|vercel/minimax-m2.7-highspeed → opencode-go\|vercel/minimax-m2.7 → anthropic\|opencode\|vercel/claude-haiku-4-5 → openai\|opencode\|vercel/gpt-5.4-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Multimodal Looker** | Vision/screenshots | openai\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/kimi-k2.5 → zai-coding-plan\|vercel/glm-4.6v → openai\|github-copilot\|opencode\|vercel/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus-Junior** | Category executor | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/kimi-k2.5 → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (medium) → opencode-go\|vercel/minimax-m2.7 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | @@ -107,7 +107,7 @@ Communicative, instruction-following, structured output. Best for agents that ne | Model | Strengths | | --------------------- | ---------------------------------------------------------------------------- | -| **Claude Opus 4.6** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. | +| **Claude Opus 4.7** | Best overall. Highest compliance with complex prompts. Default for Sisyphus. | | **Claude Sonnet 4.6** | Faster, cheaper. Good balance for everyday tasks. | | **Claude Haiku 4.5** | Fast and cheap. Good for quick tasks and utility work. | | **Kimi K2.5** | Behaves very similarly to Claude. Great all-rounder at lower cost. | @@ -130,7 +130,7 @@ 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. | +| **GPT-5.4 Mini Fast** | Default for Explore and Librarian agents. Blazing-fast reasoning-capable mini model. | | **MiniMax M2.7** | Fast and smart. Used in OpenCode Go and OpenCode Zen utility fallback chains. | | **MiniMax M2.7 Highspeed** | High-speed OpenCode catalog entry used in utility fallback chains that prefer the fastest available MiniMax path. | @@ -144,8 +144,8 @@ 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.7** | Ultra-cheap, fast responses. Used by Librarian, Atlas, and Sisyphus-Junior for utility work. | -| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used by Explore when the high-speed catalog entry is available. | +| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Atlas, Sisyphus-Junior, Explore and Librarian fallbacks for utility work. | +| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used as a secondary fallback for Explore and Librarian when GPT-5.4 Mini Fast is unavailable. | **When It Gets Used:** @@ -169,12 +169,12 @@ When agents delegate work, they don't pick a model name — they pick a **catego | Category | When Used | Fallback Chain | | -------------------- | -------------------------- | -------------------------------------------- | -| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | -| `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → opencode-go\|vercel/glm-5 | -| `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) | -| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 | +| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → zai-coding-plan\|opencode\|vercel/glm-5 → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 → kimi-for-coding/k2p5 | +| `ultrabrain` | Maximum reasoning needed | openai\|opencode\|vercel/gpt-5.4 (xhigh) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → opencode-go\|vercel/glm-5 | +| `deep` | Deep coding, complex logic | openai\|github-copilot\|venice\|opencode\|vercel/gpt-5.4 (medium) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) | +| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode\|vercel/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 | | `quick` | Simple, fast tasks | openai\|github-copilot\|opencode\|vercel/gpt-5.4-mini → anthropic\|github-copilot\|opencode\|vercel/claude-haiku-4-5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 → opencode\|vercel/gpt-5-nano | -| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-6 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 | +| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode\|vercel/claude-opus-4-7 (max) → openai\|github-copilot\|opencode\|vercel/gpt-5.4 (high) → zai-coding-plan\|opencode\|vercel/glm-5 → kimi-for-coding/k2p5 → opencode-go\|vercel/glm-5 → opencode\|vercel/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix\|vercel/kimi-k2.5 | | `unspecified-low` | General standard work | anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → openai\|opencode\|vercel/gpt-5.3-codex (medium) → opencode-go\|vercel/kimi-k2.5 → google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/minimax-m2.7 | | `writing` | Text, docs, prose | google\|github-copilot\|opencode\|vercel/gemini-3-flash → opencode-go\|vercel/kimi-k2.5 → anthropic\|github-copilot\|opencode\|vercel/claude-sonnet-4-6 → opencode-go\|vercel/minimax-m2.7 | @@ -198,7 +198,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheaper models are fine @@ -217,7 +217,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch "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" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, "visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high", @@ -234,7 +234,7 @@ See the [Orchestration System Guide](./orchestration.md) for how agents dispatch "zai-coding-plan": 10, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "opencode/gpt-5-nano": 20, }, }, diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 85aee5abf..582b5d8ba 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -225,7 +225,7 @@ When GitHub Copilot is the best available provider, install-time defaults are ag | Agent | Model | | ------------- | ---------------------------------- | -| **Sisyphus** | `github-copilot/claude-opus-4.6` | +| **Sisyphus** | `github-copilot/claude-opus-4.7` | | **Oracle** | `github-copilot/gpt-5.4` | | **Explore** | `github-copilot/grok-code-fast-1` | | **Atlas** | `github-copilot/claude-sonnet-4.6` | @@ -247,13 +247,13 @@ 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`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. +OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-7`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. When OpenCode Zen is the best available provider, these are the most relevant source-backed examples: | Agent | Model | | ------------- | ---------------------------------------------------- | -| **Sisyphus** | `opencode/claude-opus-4-6` | +| **Sisyphus** | `opencode/claude-opus-4-7` | | **Oracle** | `opencode/gpt-5.4` | | **Explore** | `opencode/minimax-m2.7` | @@ -287,7 +287,7 @@ Not all models behave the same way. Understanding which models are "similar" hel | Model | Provider(s) | Notes | | ------------------------ | ----------------------------------- | ----------------------------------------------------------------------- | -| **Claude Opus 4.6** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | +| **Claude Opus 4.7** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | | **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. | | **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. | | **Kimi K2.5** | kimi-for-coding, opencode-go, opencode, moonshotai, moonshotai-cn, firmware, ollama-cloud, aihubmix | Behaves very similarly to Claude. Great all-rounder that appears in several orchestration fallback chains. | @@ -330,8 +330,8 @@ Based on your subscriptions, here's how the agents were configured: | Agent | Role | Default Chain | What It Does | | ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- | -| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | -| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | +| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | **Dual-Prompt Agents** (auto-switch between Claude and GPT prompts): @@ -341,7 +341,7 @@ Priority: **Claude > GPT > Claude-like models** | Agent | Role | Default Chain | GPT Prompt? | | -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- | -| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | +| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | | **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Yes - GPT-optimized todo management | **GPT-Native Agents** (built for GPT, don't override to Claude): @@ -349,8 +349,8 @@ Priority: **Claude > GPT > Claude-like models** | Agent | Role | Default Chain | Notes | | -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ | | **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. | -| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | -| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | +| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | +| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-7 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | **Utility Agents** (speed over intelligence): @@ -463,7 +463,7 @@ gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/nu Tell the user of following: -1. **Sisyphus agent strongly recommends Opus 4.6 model. Using other models may result in significantly degraded experience.** +1. **Sisyphus agent strongly recommends Opus 4.7 model. Using other models may result in significantly degraded experience.** 2. **Feeling lazy?** Just include `ultrawork` (or `ulw`) in your prompt. That's it. The agent figures out the rest. diff --git a/docs/guide/orchestration.md b/docs/guide/orchestration.md index 345ebce3b..b25a93bbb 100644 --- a/docs/guide/orchestration.md +++ b/docs/guide/orchestration.md @@ -35,9 +35,9 @@ The orchestration system uses a three-layer architecture that solves context ove flowchart TB subgraph Planning["Planning Layer (Human + Prometheus)"] User[(" User")] - Prometheus[" Prometheus
(Planner)
claude-opus-4-6 / gpt-5.4 / glm-5"] - Metis[" Metis
(Consultant)
claude-opus-4-6 / gpt-5.4 / glm-5"] - Momus[" Momus
(Reviewer)
gpt-5.4 / claude-opus-4-6 / gemini-3.1-pro / glm-5"] + Prometheus[" Prometheus
(Planner)
claude-opus-4-7 / gpt-5.4 / glm-5"] + Metis[" Metis
(Consultant)
claude-opus-4-7 / gpt-5.4 / glm-5"] + Momus[" Momus
(Reviewer)
gpt-5.4 / claude-opus-4-7 / gemini-3.1-pro / glm-5"] end subgraph Execution["Execution Layer (Orchestrator)"] @@ -46,10 +46,10 @@ flowchart TB subgraph Workers["Worker Layer (Specialized Agents)"] Junior[" Sisyphus-Junior
(Task Executor)
claude-sonnet-4-6 / kimi-k2.5 / gpt-5.4 / minimax-m2.7"] - Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-6 / glm-5"] - Explore[" Explore
(Codebase Grep)
grok-code-fast-1 / minimax-m2.7-highspeed / claude-haiku-4-5"] - Librarian[" Librarian
(Docs/OSS)
minimax-m2.7 / minimax-m2.7-highspeed / claude-haiku-4-5"] - Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-6"] + Oracle[" Oracle
(Architecture)
gpt-5.4 / gemini-3.1-pro / claude-opus-4-7 / glm-5"] + Explore[" Explore
(Codebase Grep)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] + Librarian[" Librarian
(Docs/OSS)
gpt-5.4-mini-fast / minimax-m2.7-highspeed / claude-haiku-4-5"] + Frontend[" visual-engineering
(category + frontend-ui-ux)
gemini-3.1-pro / glm-5 / claude-opus-4-7"] end User -->|"Describe work"| Prometheus @@ -282,7 +282,7 @@ This "boulder pushing" mechanism is why the system is named after Sisyphus. ```typescript // OLD: Model name creates distributional bias task({ agent: "gpt-5.4", prompt: "..." }); // Model knows its limitations -task({ agent: "claude-opus-4-6", prompt: "..." }); // Different self-perception +task({ agent: "claude-opus-4-7", prompt: "..." }); // Different self-perception ``` **The Solution: Semantic Categories:** @@ -298,13 +298,13 @@ task({ category: "quick", prompt: "..." }); // "Just get it done fast" | Category | Default config | Runtime fallback order | When to Use | | -------------------- | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `glm-5` → `claude-opus-4-6` → `glm-5` → `k2p5` | Frontend, UI/UX, design, styling, animation | -| `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-6` → `glm-5` | Deep logical reasoning, complex architecture decisions | -| `deep` | `openai/gpt-5.4 medium` | `gpt-5.4` → `claude-opus-4-6` → `gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research | -| `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `claude-opus-4-6` → `gpt-5.4` | Highly creative or artistic tasks, novel ideas | +| `visual-engineering` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `glm-5` → `claude-opus-4-7` → `glm-5` → `k2p5` | Frontend, UI/UX, design, styling, animation | +| `ultrabrain` | `openai/gpt-5.4 xhigh` | `gpt-5.4` → `gemini-3.1-pro` → `claude-opus-4-7` → `glm-5` | Deep logical reasoning, complex architecture decisions | +| `deep` | `openai/gpt-5.4 medium` | `gpt-5.4` → `claude-opus-4-7` → `gemini-3.1-pro` | Goal-oriented autonomous problem-solving, thorough research | +| `artistry` | `google/gemini-3.1-pro high` | `gemini-3.1-pro` → `claude-opus-4-7` → `gpt-5.4` | Highly creative or artistic tasks, novel ideas | | `quick` | `openai/gpt-5.4-mini` | `gpt-5.4-mini` → `claude-haiku-4-5` → `gemini-3-flash` → `minimax-m2.7` → `gpt-5-nano` | Trivial tasks, single file changes, typo fixes | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | `claude-sonnet-4-6` → `gpt-5.3-codex` → `kimi-k2.5` → `gemini-3-flash` → `minimax-m2.7` | Tasks that don't fit other categories, low effort | -| `unspecified-high` | `anthropic/claude-opus-4-6 max` | `claude-opus-4-6` → `gpt-5.4` → `glm-5` → `k2p5` → `kimi-k2.5` | Tasks that don't fit other categories, high effort | +| `unspecified-high` | `anthropic/claude-opus-4-7 max` | `claude-opus-4-7` → `gpt-5.4` → `glm-5` → `k2p5` → `kimi-k2.5` | Tasks that don't fit other categories, high effort | | `writing` | `kimi-for-coding/k2p5` | `gemini-3-flash` → `kimi-k2.5` → `claude-sonnet-4-6` → `minimax-m2.7` | Documentation, prose, technical writing | ### Skills: Domain-Specific Instructions @@ -423,7 +423,7 @@ Atlas is automatically activated when you run `/start-work`. You don't need to m | Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` | | --------------- | ------------------------------------------ | ---------------------------------------------------- | -| **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-6` / `kimi-k2.5` / `gpt-5.4` / `glm-5` depending on setup | +| **Model** | `gpt-5.4` (`medium`) | `claude-opus-4-7` / `kimi-k2.5` / `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 | diff --git a/docs/guide/overview.md b/docs/guide/overview.md index 5e4501920..cf1bb783c 100644 --- a/docs/guide/overview.md +++ b/docs/guide/overview.md @@ -82,11 +82,11 @@ Sisyphus is your main orchestrator. He plans, delegates to specialists, and driv **Recommended models:** -- **Claude Opus 4.6** — Best overall experience. Sisyphus was built with Claude-optimized prompts. +- **Claude Opus 4.7** — Best overall experience. Sisyphus was built with Claude-optimized prompts. - **Kimi K2.5** — Great Claude-like alternative. Many users run this combo exclusively. - **GLM 5** — Solid option, especially via Z.ai. -Sisyphus works best on Claude Opus 4.6, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead. +Sisyphus works best on Claude Opus 4.7, Kimi K2.5, and GLM 5. GPT-5.4 now has a dedicated prompt path, but older GPT models are still a poor fit and should route to Hephaestus instead. ### Hephaestus: The Legitimate Craftsman @@ -173,7 +173,7 @@ You can override specific agents or categories in your config: // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheaper models are fine @@ -207,10 +207,10 @@ You can override specific agents or categories in your config: "unspecified-low": { "model": "openai/gpt-5.4-mini" }, // High-effort fallback: best available - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, // Prose and documentation - "writing": { "model": "anthropic/claude-opus-4-6", "variant": "high" }, + "writing": { "model": "anthropic/claude-opus-4-7", "variant": "high" }, }, } ``` @@ -219,7 +219,7 @@ You can override specific agents or categories in your config: **Claude-like models** (instruction-following, structured output): -- Claude Opus 4.6, Claude Haiku 4.5 +- Claude Opus 4.7, Claude Haiku 4.5 - Kimi K2.5 — behaves very similarly to Claude - GLM 5 — Claude-like behavior, good for broad tasks diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index d37b9104b..3f59a7f7c 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -78,7 +78,7 @@ Here's a practical starting configuration: // Main orchestrator: Claude Opus or Kimi K2.5 work best "sisyphus": { "model": "kimi-for-coding/k2p5", - "ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "ultrawork": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, }, // Research agents: cheap fast models are fine @@ -102,7 +102,7 @@ Here's a practical starting configuration: "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, // unspecified-high - complex work - "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, + "unspecified-high": { "model": "anthropic/claude-opus-4-7", "variant": "max" }, // writing - docs/prose "writing": { "model": "google/gemini-3-flash" }, @@ -130,7 +130,7 @@ Here's a practical starting configuration: "zai-coding-plan": 10, }, "modelConcurrency": { - "anthropic/claude-opus-4-6": 2, + "anthropic/claude-opus-4-7": 2, "opencode/gpt-5-nano": 20, }, }, @@ -229,7 +229,7 @@ Control what tools an agent can use: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ // Simple string fallback "openai/gpt-5.4", @@ -293,7 +293,7 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega | `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort | -| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort | +| `unspecified-high` | `anthropic/claude-opus-4-7` (max) | General tasks, high effort | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | > **Note**: Built-in defaults only apply if the category is present in your config. Otherwise the system default model is used. @@ -355,28 +355,28 @@ Capability data comes from provider runtime metadata first. OmO also ships bundl | Agent | Default Model | Provider Priority | | --------------------- | ------------------- | ---------------------------------------------------------------------------- | -| **Sisyphus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | +| **Sisyphus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle` | | **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | -| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` | -| **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7` → `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | -| **explore** | `grok-code-fast-1` | `github-copilot\|xai/grok-code-fast-1` → `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano` | +| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | +| **librarian** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go\|vercel/minimax-m2.7-highspeed` → `opencode-go\|vercel/minimax-m2.7` → `anthropic\|opencode\|vercel/claude-haiku-4-5` → `openai\|opencode\|vercel/gpt-5.4-nano` | +| **explore** | `gpt-5.4-mini-fast` | `openai/gpt-5.4-mini-fast` → `opencode-go\|vercel/minimax-m2.7-highspeed` → `opencode-go\|vercel/minimax-m2.7` → `anthropic\|opencode\|vercel/claude-haiku-4-5` → `openai\|opencode\|vercel/gpt-5.4-nano` | | **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)` → `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano` | -| **Prometheus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | -| **Metis** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | -| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5` | +| **Prometheus** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro` | +| **Metis** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | +| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5` | | **Atlas** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `opencode-go/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `opencode-go/minimax-m2.7` | #### Category Provider Chains | Category | Default Model | Provider Priority | | ---------------------- | ------------------- | -------------------------------------------------------------- | -| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `zai-coding-plan\|opencode/glm-5` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | -| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5` | -| **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` | -| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4` | +| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `zai-coding-plan\|opencode/glm-5` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5` | +| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5` | +| **deep** | `gpt-5.4` | `openai\|github-copilot\|venice\|opencode/gpt-5.4 (medium)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` | +| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4` | | **quick** | `gpt-5.4-mini` | `openai\|github-copilot\|opencode/gpt-5.4-mini` → `anthropic\|github-copilot\|opencode/claude-haiku-4-5` → `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/minimax-m2.7` → `opencode/gpt-5-nano` | | **unspecified-low** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `openai\|opencode/gpt-5.3-codex (medium)` → `opencode-go/kimi-k2.5` → `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/minimax-m2.7` | -| **unspecified-high** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `zai-coding-plan\|opencode/glm-5` → `kimi-for-coding/k2p5` → `opencode-go/glm-5` → `opencode/kimi-k2.5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | +| **unspecified-high** | `claude-opus-4-7` | `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `zai-coding-plan\|opencode/glm-5` → `kimi-for-coding/k2p5` → `opencode-go/glm-5` → `opencode/kimi-k2.5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | | **writing** | `gemini-3-flash` | `google\|github-copilot\|opencode/gemini-3-flash` → `opencode-go/kimi-k2.5` → `anthropic\|github-copilot\|opencode/claude-sonnet-4-6` → `opencode-go/minimax-m2.7` | Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config. @@ -395,7 +395,7 @@ Control parallel agent execution and concurrency limits. "defaultConcurrency": 5, "staleTimeoutMs": 180000, "providerConcurrency": { "anthropic": 3, "openai": 5, "google": 10 }, - "modelConcurrency": { "anthropic/claude-opus-4-6": 2 } + "modelConcurrency": { "anthropic/claude-opus-4-7": 2 } } } ``` @@ -678,7 +678,7 @@ Define `fallback_models` per agent or category: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -697,7 +697,7 @@ Define `fallback_models` per agent or category: { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -798,7 +798,7 @@ Mix string entries and object entries when only some fallback models need specia { "agents": { "sisyphus": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "fallback_models": [ "openai/gpt-5.4", { @@ -832,7 +832,7 @@ Mix string entries and object entries when only some fallback models need specia "maxTokens": 12000 }, { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "variant": "max", "temperature": 0.2 }, diff --git a/docs/reference/features.md b/docs/reference/features.md index d79c11ec1..ab5f3925c 100644 --- a/docs/reference/features.md +++ b/docs/reference/features.md @@ -10,19 +10,19 @@ Core-agent tab cycling is deterministic via injected runtime order field. The fi | 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: `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/big-pickle`. | +| **Sisyphus** | `claude-opus-4-7` | 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: `opencode-go/kimi-k2.5` → `kimi-for-coding/k2p5` → `opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` → `openai\|github-copilot\|opencode/gpt-5.4 (medium)` → `zai-coding-plan\|opencode/glm-5` → `opencode/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: `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `opencode-go/glm-5`. | -| **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode/minimax-m2.7-highspeed` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | -| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `opencode/gpt-5-nano`. | +| **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `opencode-go/glm-5`. | +| **Librarian** | `gpt-5.4-mini-fast` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano`. | +| **Explore** | `gpt-5.4-mini-fast` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed` → `opencode-go/minimax-m2.7` → `anthropic\|opencode/claude-haiku-4-5` → `openai\|opencode/gpt-5.4-nano`. | | **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5` → `zai-coding-plan/glm-4.6v` → `openai\|github-copilot\|opencode/gpt-5-nano`. | ### Planning Agents | Agent | Model | Purpose | | -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Prometheus** | `claude-opus-4-6` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro`. | -| **Metis** | `claude-opus-4-6` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5`. | -| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5`. | +| **Prometheus** | `claude-opus-4-7` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `google\|github-copilot\|opencode/gemini-3.1-pro`. | +| **Metis** | `claude-opus-4-7` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)` → `opencode-go/glm-5` → `kimi-for-coding/k2p5`. | +| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-7 (max)` → `google\|github-copilot\|opencode/gemini-3.1-pro (high)` → `opencode-go/glm-5`. | ### Orchestration Agents @@ -115,7 +115,7 @@ By combining these two concepts, you can generate optimal agents through `task`. | `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas | | `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required | -| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required | +| `unspecified-high` | `anthropic/claude-opus-4-7` (max) | Tasks that don't fit other categories, high effort required | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | ### Usage @@ -138,7 +138,7 @@ You can define custom categories in your plugin config file. During the rename t | Field | Type | Description | | ------------------- | ------- | --------------------------------------------------------------------------- | | `description` | string | Human-readable description of the category's purpose. Shown in task prompt. | -| `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-6`) | +| `model` | string | AI model ID to use (e.g., `anthropic/claude-opus-4-7`) | | `variant` | string | Model variant (e.g., `max`, `xhigh`) | | `temperature` | number | Creativity level (0.0 ~ 2.0). Lower is more deterministic. | | `top_p` | number | Nucleus sampling parameter (0.0 ~ 1.0) | @@ -170,7 +170,7 @@ You can define custom categories in your plugin config file. During the rename t // 3. Configure thinking model and restrict tools "deep-reasoning": { - "model": "anthropic/claude-opus-4-6", + "model": "anthropic/claude-opus-4-7", "thinking": { "type": "enabled", "budgetTokens": 32000, diff --git a/package.json b/package.json index ab4576f04..d00e0e274 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "oh-my-opencode", - "version": "3.17.3", + "version": "3.17.4", "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools", "main": "./dist/index.js", "types": "dist/index.d.ts", "type": "module", "bin": { - "oh-my-opencode": "bin/oh-my-opencode.js" + "oh-my-opencode": "bin/oh-my-opencode.js", + "oh-my-openagent": "bin/oh-my-opencode.js" }, "files": [ "dist", @@ -21,7 +22,7 @@ "./schema.json": "./dist/oh-my-opencode.schema.json" }, "scripts": { - "build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", + "build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema", "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", @@ -69,32 +70,35 @@ "picocolors": "^1.1.1", "picomatch": "^4.0.2", "posthog-node": "^5.29.2", - "vscode-jsonrpc": "^8.2.0", - "zod": "^4.3.0" + "vscode-jsonrpc": "^8.2.0" }, "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/picomatch": "^3.0.2", "bun-types": "1.3.11", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "zod": "^4.3.0" }, "optionalDependencies": { - "oh-my-opencode-darwin-arm64": "3.17.2", - "oh-my-opencode-darwin-x64": "3.17.2", - "oh-my-opencode-darwin-x64-baseline": "3.17.2", - "oh-my-opencode-linux-arm64": "3.17.2", - "oh-my-opencode-linux-arm64-musl": "3.17.2", - "oh-my-opencode-linux-x64": "3.17.2", - "oh-my-opencode-linux-x64-baseline": "3.17.2", - "oh-my-opencode-linux-x64-musl": "3.17.2", - "oh-my-opencode-linux-x64-musl-baseline": "3.17.2", - "oh-my-opencode-windows-x64": "3.17.2", - "oh-my-opencode-windows-x64-baseline": "3.17.2" + "oh-my-opencode-darwin-arm64": "3.17.4", + "oh-my-opencode-darwin-x64": "3.17.4", + "oh-my-opencode-darwin-x64-baseline": "3.17.4", + "oh-my-opencode-linux-arm64": "3.17.4", + "oh-my-opencode-linux-arm64-musl": "3.17.4", + "oh-my-opencode-linux-x64": "3.17.4", + "oh-my-opencode-linux-x64-baseline": "3.17.4", + "oh-my-opencode-linux-x64-musl": "3.17.4", + "oh-my-opencode-linux-x64-musl-baseline": "3.17.4", + "oh-my-opencode-windows-x64": "3.17.4", + "oh-my-opencode-windows-x64-baseline": "3.17.4" }, "overrides": {}, "trustedDependencies": [ "@ast-grep/cli", "@ast-grep/napi", "@code-yeongyu/comment-checker" - ] + ], + "peerDependencies": { + "zod": "^4.0.0" + } } diff --git a/packages/darwin-arm64/package.json b/packages/darwin-arm64/package.json index de3a68cba..ccf706faf 100644 --- a/packages/darwin-arm64/package.json +++ b/packages/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-arm64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-arm64)", "license": "MIT", "repository": { diff --git a/packages/darwin-x64-baseline/package.json b/packages/darwin-x64-baseline/package.json index 7533b735d..ac965d73f 100644 --- a/packages/darwin-x64-baseline/package.json +++ b/packages/darwin-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/darwin-x64/package.json b/packages/darwin-x64/package.json index cd086e99c..710360fdb 100644 --- a/packages/darwin-x64/package.json +++ b/packages/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-darwin-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (darwin-x64)", "license": "MIT", "repository": { diff --git a/packages/linux-arm64-musl/package.json b/packages/linux-arm64-musl/package.json index 8cb386b19..ade0dd78f 100644 --- a/packages/linux-arm64-musl/package.json +++ b/packages/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-arm64-musl", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)", "license": "MIT", "repository": { diff --git a/packages/linux-arm64/package.json b/packages/linux-arm64/package.json index d74e1c262..f4ac2294d 100644 --- a/packages/linux-arm64/package.json +++ b/packages/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-arm64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-arm64)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-baseline/package.json b/packages/linux-x64-baseline/package.json index bf71d1299..a0d51f8bc 100644 --- a/packages/linux-x64-baseline/package.json +++ b/packages/linux-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-musl-baseline/package.json b/packages/linux-x64-musl-baseline/package.json index 4b89d7bd6..3515050ab 100644 --- a/packages/linux-x64-musl-baseline/package.json +++ b/packages/linux-x64-musl-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-musl-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/linux-x64-musl/package.json b/packages/linux-x64-musl/package.json index f65f8daf3..528e60b0e 100644 --- a/packages/linux-x64-musl/package.json +++ b/packages/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64-musl", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)", "license": "MIT", "repository": { diff --git a/packages/linux-x64/package.json b/packages/linux-x64/package.json index 9ce7cc1da..621ba280b 100644 --- a/packages/linux-x64/package.json +++ b/packages/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-linux-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (linux-x64)", "license": "MIT", "repository": { diff --git a/packages/windows-x64-baseline/package.json b/packages/windows-x64-baseline/package.json index b26c90ed1..78a9ae8f9 100644 --- a/packages/windows-x64-baseline/package.json +++ b/packages/windows-x64-baseline/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-windows-x64-baseline", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)", "license": "MIT", "repository": { diff --git a/packages/windows-x64/package.json b/packages/windows-x64/package.json index 002bd9d5a..8b6d80e6d 100644 --- a/packages/windows-x64/package.json +++ b/packages/windows-x64/package.json @@ -1,6 +1,6 @@ { "name": "oh-my-opencode-windows-x64", - "version": "3.17.2", + "version": "3.17.4", "description": "Platform-specific binary for oh-my-opencode (windows-x64)", "license": "MIT", "repository": { diff --git a/signatures/cla.json b/signatures/cla.json index e16dee644..dddea1ad0 100644 --- a/signatures/cla.json +++ b/signatures/cla.json @@ -2831,6 +2831,70 @@ "created_at": "2026-04-15T05:03:42Z", "repoId": 1108837393, "pullRequestNo": 3440 + }, + { + "name": "CHLK", + "id": 30882682, + "comment_id": 4252344048, + "created_at": "2026-04-15T13:10:30Z", + "repoId": 1108837393, + "pullRequestNo": 3455 + }, + { + "name": "omer-koren", + "id": 54630488, + "comment_id": 4257838546, + "created_at": "2026-04-16T06:34:57Z", + "repoId": 1108837393, + "pullRequestNo": 3470 + }, + { + "name": "EnochLi15", + "id": 38340798, + "comment_id": 4259785224, + "created_at": "2026-04-16T11:45:01Z", + "repoId": 1108837393, + "pullRequestNo": 3473 + }, + { + "name": "Disaster-Terminator", + "id": 47147571, + "comment_id": 4272328109, + "created_at": "2026-04-18T01:42:07Z", + "repoId": 1108837393, + "pullRequestNo": 3497 + }, + { + "name": "Netzhangheng", + "id": 25896014, + "comment_id": 4272702675, + "created_at": "2026-04-18T04:24:37Z", + "repoId": 1108837393, + "pullRequestNo": 3499 + }, + { + "name": "andomeder", + "id": 33397443, + "comment_id": 4273945668, + "created_at": "2026-04-18T14:55:50Z", + "repoId": 1108837393, + "pullRequestNo": 3514 + }, + { + "name": "CoderLuii", + "id": 203967356, + "comment_id": 4275088581, + "created_at": "2026-04-19T03:28:19Z", + "repoId": 1108837393, + "pullRequestNo": 3518 + }, + { + "name": "aschina", + "id": 31149103, + "comment_id": 4287617163, + "created_at": "2026-04-21T10:00:13Z", + "repoId": 1108837393, + "pullRequestNo": 3560 } ] } \ No newline at end of file diff --git a/src/AGENTS.md b/src/AGENTS.md index 255bd8ea6..7db7929a7 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -1,6 +1,6 @@ # src/ — Plugin Source -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW @@ -10,7 +10,7 @@ Entry point `index.ts` orchestrates 5-step initialization: loadConfig → create | File | Purpose | |------|---------| -| `index.ts` | Plugin entry, exports `OhMyOpenCodePlugin` | +| `index.ts` | Plugin entry, default-exports `pluginModule: PluginModule` with `{ id, server }` | | `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation | | `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler | | `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) | diff --git a/src/__tests__/perf/fixtures/in-tree/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/AGENTS.md new file mode 100644 index 000000000..22257f9ad --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/AGENTS.md @@ -0,0 +1 @@ +# fixture root diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md new file mode 100644 index 000000000..6bc3f0b2c --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/AGENTS.md @@ -0,0 +1 @@ +# fixture package diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts new file mode 100644 index 000000000..dad26290a --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-16.ts @@ -0,0 +1 @@ +export const file16 = 16 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts new file mode 100644 index 000000000..01e60135f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-17.ts @@ -0,0 +1 @@ +export const file17 = 17 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts new file mode 100644 index 000000000..000ce187b --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-18.ts @@ -0,0 +1 @@ +export const file18 = 18 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts new file mode 100644 index 000000000..43ebccb94 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-19.ts @@ -0,0 +1 @@ +export const file19 = 19 diff --git a/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts new file mode 100644 index 000000000..763bfe44f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/packages/pkg-one/src/file-20.ts @@ -0,0 +1 @@ +export const file20 = 20 diff --git a/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md b/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md new file mode 100644 index 000000000..df55bdcda --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/AGENTS.md @@ -0,0 +1 @@ +# fixture src diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts new file mode 100644 index 000000000..8a4e4907d --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-01.ts @@ -0,0 +1 @@ +export const file01 = 1 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts new file mode 100644 index 000000000..20ca96c14 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-02.ts @@ -0,0 +1 @@ +export const file02 = 2 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts new file mode 100644 index 000000000..b7a0ab9bd --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-03.ts @@ -0,0 +1 @@ +export const file03 = 3 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts new file mode 100644 index 000000000..5917ea7a4 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-04.ts @@ -0,0 +1 @@ +export const file04 = 4 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts new file mode 100644 index 000000000..7c842b808 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-05.ts @@ -0,0 +1 @@ +export const file05 = 5 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts new file mode 100644 index 000000000..b48d2d1cd --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-06.ts @@ -0,0 +1 @@ +export const file06 = 6 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts new file mode 100644 index 000000000..9de6f660f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-07.ts @@ -0,0 +1 @@ +export const file07 = 7 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts new file mode 100644 index 000000000..2f24a3912 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-08.ts @@ -0,0 +1 @@ +export const file08 = 8 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts new file mode 100644 index 000000000..2c4cddbd4 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-09.ts @@ -0,0 +1 @@ +export const file09 = 9 diff --git a/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts b/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts new file mode 100644 index 000000000..1d329a0dc --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/app/file-10.ts @@ -0,0 +1 @@ +export const file10 = 10 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts new file mode 100644 index 000000000..eb1a64844 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-11.ts @@ -0,0 +1 @@ +export const file11 = 11 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts new file mode 100644 index 000000000..6dbff13ec --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-12.ts @@ -0,0 +1 @@ +export const file12 = 12 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts new file mode 100644 index 000000000..5a46ab064 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-13.ts @@ -0,0 +1 @@ +export const file13 = 13 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts new file mode 100644 index 000000000..32824f748 --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-14.ts @@ -0,0 +1 @@ +export const file14 = 14 diff --git a/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts b/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts new file mode 100644 index 000000000..c0d19485f --- /dev/null +++ b/src/__tests__/perf/fixtures/in-tree/src/lib/file-15.ts @@ -0,0 +1 @@ +export const file15 = 15 diff --git a/src/__tests__/perf/plugin-init.test.ts b/src/__tests__/perf/plugin-init.test.ts new file mode 100644 index 000000000..1450b6557 --- /dev/null +++ b/src/__tests__/perf/plugin-init.test.ts @@ -0,0 +1,121 @@ +import { cpSync, mkdirSync, mkdtempSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" + +import type { PluginInput } from "@opencode-ai/plugin" +import { createOpencodeClient } from "@opencode-ai/sdk" +import { describe, expect, it } from "bun:test" + +type InitMetrics = { + coldMs: number + warmMs: [number, number] + medianMs: number +} + +function getMedian(values: number[]): number { + const sorted = [...values].sort((left, right) => left - right) + return sorted[Math.floor(sorted.length / 2)] ?? 0 +} + +function createPluginInput(directory: string): PluginInput { + const client = createOpencodeClient({ directory }) + + return { + client, + project: { + id: `perf-${Date.now()}`, + worktree: directory, + time: { created: Date.now() }, + }, + directory, + worktree: directory, + serverUrl: new URL("http://localhost"), + $: Bun.$, + } +} + +async function importFreshPluginModule(): Promise<(typeof import("../../index"))["default"]> { + const token = `${Date.now()}-${Math.random()}` + return (await import(`../../index?perf=${token}`)).default +} + +async function measureInitMetrics(directory: string): Promise { + const pluginModule = await importFreshPluginModule() + const measurements: number[] = [] + + for (let index = 0; index < 3; index += 1) { + const input = createPluginInput(directory) + const start = performance.now() + await pluginModule.server(input, {}) + measurements.push(performance.now() - start) + } + + return { + coldMs: measurements[0] ?? 0, + warmMs: [measurements[1] ?? 0, measurements[2] ?? 0], + medianMs: getMedian(measurements), + } +} + +async function measureScenario( + label: string, + populateDirectory: (directory: string) => void, +): Promise { + const rootDirectory = mkdtempSync(join(tmpdir(), "perf-d09-")) + const projectDirectory = join(rootDirectory, label) + const configDirectory = join(rootDirectory, "opencode-config") + const previousConfigDirectory = process.env.OPENCODE_CONFIG_DIR + + mkdirSync(configDirectory, { recursive: true }) + process.env.OPENCODE_CONFIG_DIR = configDirectory + + try { + populateDirectory(projectDirectory) + return await measureInitMetrics(projectDirectory) + } finally { + if (previousConfigDirectory === undefined) { + delete process.env.OPENCODE_CONFIG_DIR + } else { + process.env.OPENCODE_CONFIG_DIR = previousConfigDirectory + } + + rmSync(rootDirectory, { recursive: true, force: true }) + } +} + +function logMetrics(label: string, metrics: InitMetrics): void { + console.info( + `${label}: cold=${metrics.coldMs.toFixed(1)}ms warm=[${metrics.warmMs.map((value) => value.toFixed(1)).join(", ")}] median=${metrics.medianMs.toFixed(1)}ms`, + ) +} + +describe("plugin init performance", () => { + it("stays within the empty project init budget", async () => { + // given + const metrics = await measureScenario("empty-project", (directory) => { + mkdirSync(directory, { recursive: true }) + }) + + // when + logMetrics("empty-project", metrics) + + // then + // regression budget + expect(metrics.medianMs).toBeLessThan(500) + }) + + it("stays within the in-tree fixture init budget", async () => { + // given + const fixtureDirectory = new URL("./fixtures/in-tree/", import.meta.url) + const metrics = await measureScenario("in-tree-fixture", (directory) => { + cpSync(fixtureDirectory, directory, { recursive: true }) + }) + + // when + logMetrics("in-tree-fixture", metrics) + + // then + // regression budget + expect(metrics.medianMs).toBeLessThan(700) + }) +}) diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index 137658b1f..c69c0608a 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -1,6 +1,6 @@ # src/agents/ — 11 Agent Definitions -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW @@ -10,16 +10,16 @@ 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 | +| **Sisyphus** | claude-opus-4-7 max | 0.1 | all | k2p5 -> kimi-k2.5 -> gpt-5.4 medium -> glm-5 -> big-pickle | Main orchestrator, plans + delegates | | **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** | 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 | +| **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high -> claude-opus-4-7 max | Read-only consultation | +| **Librarian** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-nano | External docs/code search | +| **Explore** | gpt-5.4-mini-fast | 0.1 | subagent | minimax-m2.7-highspeed -> minimax-m2.7 -> claude-haiku-4-5 -> gpt-5.4-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 | +| **Metis** | claude-opus-4-7 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-7 max -> gemini-3.1-pro high | Plan reviewer | | **Atlas** | claude-sonnet-4-6 | 0.1 | primary | gpt-5.4 medium | Todo-list orchestrator | -| **Prometheus** | claude-opus-4-6 max | 0.1 | — | internal planner | Strategic planner (internal) | +| **Prometheus** | claude-opus-4-7 max | 0.1 | — | internal planner | Strategic planner (internal) | | **Sisyphus-Junior** | claude-sonnet-4-6 | 0.1 | all | user-configurable | Category-spawned executor | ## TOOL RESTRICTIONS diff --git a/src/agents/agent-identity.test.ts b/src/agents/agent-identity.test.ts index 1247cda17..2c6a568a8 100644 --- a/src/agents/agent-identity.test.ts +++ b/src/agents/agent-identity.test.ts @@ -57,7 +57,7 @@ describe("Sisyphus prompt identity", () => { describe("#given a Sisyphus agent created with default model", () => { describe("#when checking the prompt", () => { it("#then contains the agent identity section with override directive", () => { - const config = createSisyphusAgent("anthropic/claude-opus-4-6") + const config = createSisyphusAgent("anthropic/claude-opus-4-7") expect(config.prompt).toContain("") expect(config.prompt).toContain("Sisyphus") @@ -65,7 +65,7 @@ describe("Sisyphus prompt identity", () => { }) it("#then identity section appears before the Role section", () => { - const config = createSisyphusAgent("anthropic/claude-opus-4-6") + const config = createSisyphusAgent("anthropic/claude-opus-4-7") const prompt = config.prompt ?? "" const identityIndex = prompt.indexOf("") const roleIndex = prompt.indexOf("") @@ -115,7 +115,7 @@ describe("Agent identity preservation through overrides", () => { describe("#given a Sisyphus agent with prompt_append override", () => { describe("#when merging the override", () => { it("#then identity section is preserved in the merged prompt", () => { - const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") + const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7") const merged = mergeAgentConfig(baseConfig, { prompt_append: "Extra instructions here" }) expect(merged.prompt).toContain("") @@ -129,7 +129,7 @@ describe("Agent identity preservation through overrides", () => { describe("#given a Sisyphus agent with model override only", () => { describe("#when merging the override", () => { it("#then identity section is preserved unchanged", () => { - const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-6") + const baseConfig = createSisyphusAgent("anthropic/claude-opus-4-7") const merged = mergeAgentConfig(baseConfig, { model: "openai/gpt-5.4" }) expect(merged.prompt).toContain("") diff --git a/src/agents/atlas/default-prompt-sections.ts b/src/agents/atlas/default-prompt-sections.ts index 46e2634f7..24ba9f807 100644 --- a/src/agents/atlas/default-prompt-sections.ts +++ b/src/agents/atlas/default-prompt-sections.ts @@ -150,16 +150,16 @@ task( ### 3.5 Handle Failures (USE RESUME) -**CRITICAL: When re-delegating, ALWAYS use \`session_id\` parameter.** +**CRITICAL: When re-delegating, ALWAYS use \`task_id\` parameter.** -Every \`task()\` output includes a session_id. STORE IT. +Every \`task()\` output includes a task_id. STORE IT. If task fails: 1. Identify what went wrong 2. **Resume the SAME session** - subagent has full context already: \`\`\`typescript task( - session_id="ses_xyz789", // Session from failed task + task_id="ses_xyz789", // Task ID from failed task load_skills=[...], prompt="FAILED: {error}. Fix by: {specific instruction}" ) @@ -167,7 +167,7 @@ If task fails: 3. Maximum 3 retry attempts with the SAME session 4. If blocked after 3 attempts: Document and continue to independent tasks -**Why session_id is MANDATORY for failures:** +**Why task_id is MANDATORY for failures:** - Subagent already read all files, knows the context - No repeated exploration = 70%+ token savings - Subagent knows what approaches already failed @@ -292,6 +292,6 @@ export const DEFAULT_ATLAS_CRITICAL_RULES = ` - Pass inherited wisdom to every subagent - Parallelize independent tasks - Verify with your own tools -- **Store session_id from every delegation output** -- **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups** +- **Store task_id from every delegation output** +- **Use \`task_id="{task_id}"\` for retries, fixes, and follow-ups** ` diff --git a/src/agents/atlas/gemini-prompt-sections.ts b/src/agents/atlas/gemini-prompt-sections.ts index 7a84e3d73..2ca4c2bc2 100644 --- a/src/agents/atlas/gemini-prompt-sections.ts +++ b/src/agents/atlas/gemini-prompt-sections.ts @@ -164,10 +164,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden ### 3.5 Handle Failures -**CRITICAL: Use \`session_id\` for retries.** +**CRITICAL: Use \`task_id\` for retries.** \`\`\`typescript -task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") +task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") \`\`\` - Maximum 3 retries per task diff --git a/src/agents/atlas/gpt-prompt-sections.ts b/src/agents/atlas/gpt-prompt-sections.ts index 96977f777..1a9f39c26 100644 --- a/src/agents/atlas/gpt-prompt-sections.ts +++ b/src/agents/atlas/gpt-prompt-sections.ts @@ -169,10 +169,10 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden ### 3.5 Handle Failures -**CRITICAL: Use \`session_id\` for retries.** +**CRITICAL: Use \`task_id\` for retries.** \`\`\`typescript -task(session_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") +task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}") \`\`\` - Maximum 3 retries per task diff --git a/src/agents/builtin-agents/sisyphus-agent.test.ts b/src/agents/builtin-agents/sisyphus-agent.test.ts index e55fea125..e7289f6c0 100644 --- a/src/agents/builtin-agents/sisyphus-agent.test.ts +++ b/src/agents/builtin-agents/sisyphus-agent.test.ts @@ -43,7 +43,7 @@ describe("maybeCreateSisyphusConfig", () => { // given const agentOverrides: AgentOverrides = { sisyphus: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", permission: { apply_patch: "allow", }, @@ -55,8 +55,8 @@ describe("maybeCreateSisyphusConfig", () => { const config = maybeCreateSisyphusConfig({ disabledAgents: [], agentOverrides, - availableModels: new Set(["anthropic/claude-opus-4-6"]), - systemDefaultModel: "anthropic/claude-opus-4-6", + availableModels: new Set(["anthropic/claude-opus-4-7"]), + systemDefaultModel: "anthropic/claude-opus-4-7", isFirstRunNoCache: false, availableAgents: [], availableSkills: [], @@ -67,7 +67,7 @@ describe("maybeCreateSisyphusConfig", () => { // then expect(config).toBeDefined(); - expect(config?.model).toBe("anthropic/claude-opus-4-6"); + expect(config?.model).toBe("anthropic/claude-opus-4-7"); // Claude models should allow the user override expect(config?.permission).toHaveProperty("apply_patch", "allow"); }); diff --git a/src/agents/custom-agent-orchestrator-visibility.test.ts b/src/agents/custom-agent-orchestrator-visibility.test.ts index c0b709e4b..b526d3f9f 100644 --- a/src/agents/custom-agent-orchestrator-visibility.test.ts +++ b/src/agents/custom-agent-orchestrator-visibility.test.ts @@ -2,13 +2,13 @@ import { describe, expect, spyOn, test } from "bun:test" import { createBuiltinAgents } from "./builtin-agents" import * as shared from "../shared" -const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" +const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7" describe("createBuiltinAgents custom agent visibility", () => { test("#given runtime custom agents #when orchestrator prompts are built #then custom agents are not advertised for automatic delegation", async () => { //#given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) try { diff --git a/src/agents/dynamic-agent-core-sections.ts b/src/agents/dynamic-agent-core-sections.ts index dc91fd480..416750a54 100644 --- a/src/agents/dynamic-agent-core-sections.ts +++ b/src/agents/dynamic-agent-core-sections.ts @@ -182,7 +182,7 @@ Multi-step task? **ALWAYS consult Plan Agent first.** Do NOT start implementatio - Single-file fix or trivial change → proceed directly - Anything else (2+ steps, unclear scope, architecture) → \`task(subagent_type="plan", ...)\` FIRST -- Use \`session_id\` to resume the same Plan Agent - ask follow-up questions aggressively +- Use \`task_id\` to resume the same Plan Agent - ask follow-up questions aggressively - If ANY part of the task is ambiguous, ask Plan Agent before guessing Plan Agent returns a structured work breakdown with parallel execution opportunities. Follow it.` diff --git a/src/agents/dynamic-agent-prompt-builder.test.ts b/src/agents/dynamic-agent-prompt-builder.test.ts index 7fab72a75..7e4b57305 100644 --- a/src/agents/dynamic-agent-prompt-builder.test.ts +++ b/src/agents/dynamic-agent-prompt-builder.test.ts @@ -211,7 +211,7 @@ describe("buildParallelDelegationSection", () => { it("#given Claude model #when building #then returns empty", () => { //#given - const model = "anthropic/claude-opus-4-6" + const model = "anthropic/claude-opus-4-7" const categories = [deepCategory] //#when @@ -244,7 +244,7 @@ describe("buildNonClaudePlannerSection", () => { //#then expect(result).toContain("Plan Agent") - expect(result).toContain("session_id") + expect(result).toContain("task_id") expect(result).toContain("Multi-step") }) diff --git a/src/agents/explore.ts b/src/agents/explore.ts index c62cc9993..3449ee346 100644 --- a/src/agents/explore.ts +++ b/src/agents/explore.ts @@ -25,13 +25,10 @@ export const EXPLORE_PROMPT_METADATA: AgentPromptMetadata = { } export function createExploreAgent(model: string): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "apply_patch", - "task", - "call_omo_agent", - ]) + const restrictions = createAgentToolRestrictions( + ["write", "edit", "apply_patch", "task", "call_omo_agent"], + ["lsp_symbols", "lsp_goto_definition", "lsp_find_references", "lsp_diagnostics", "ast_grep_search"], + ) return { description: diff --git a/src/agents/hephaestus/agent.test.ts b/src/agents/hephaestus/agent.test.ts index 7818e0361..5721f006a 100644 --- a/src/agents/hephaestus/agent.test.ts +++ b/src/agents/hephaestus/agent.test.ts @@ -56,7 +56,7 @@ describe("getHephaestusPromptSource", () => { test("returns 'gpt' for non-GPT models and undefined", () => { // given - const model1 = "anthropic/claude-opus-4-6"; + const model1 = "anthropic/claude-opus-4-7"; const model2 = undefined; // when @@ -124,7 +124,7 @@ describe("getHephaestusPrompt", () => { test("Claude model returns generic GPT prompt (Hephaestus default)", () => { // given - const model = "anthropic/claude-opus-4-6"; + const model = "anthropic/claude-opus-4-7"; // when const prompt = getHephaestusPrompt(model); @@ -149,7 +149,7 @@ describe("getHephaestusPrompt", () => { test("useTaskSystem=false includes Todo Discipline for Claude models", () => { // given - const model = "anthropic/claude-opus-4-6"; + const model = "anthropic/claude-opus-4-7"; // when const prompt = getHephaestusPrompt(model, false); @@ -239,7 +239,7 @@ describe("createHephaestusAgent", () => { // given const gpt54Model = "openai/gpt-5.4"; const gptGenericModel = "openai/gpt-4o"; - const claudeModel = "anthropic/claude-opus-4-6"; + const claudeModel = "anthropic/claude-opus-4-7"; // when const gpt54Config = createHephaestusAgent(gpt54Model); @@ -322,7 +322,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { // given const agentOverrides: AgentOverrides = { hephaestus: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", permission: { apply_patch: "allow", }, @@ -334,8 +334,8 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { const config = maybeCreateHephaestusConfig({ disabledAgents: [], agentOverrides, - availableModels: new Set(["anthropic/claude-opus-4-6"]), - systemDefaultModel: "anthropic/claude-opus-4-6", + availableModels: new Set(["anthropic/claude-opus-4-7"]), + systemDefaultModel: "anthropic/claude-opus-4-7", isFirstRunNoCache: false, availableAgents: [], availableSkills: [], @@ -346,7 +346,7 @@ describe("maybeCreateHephaestusConfig GPT apply_patch guard", () => { // then expect(config).toBeDefined(); - expect(config?.model).toBe("anthropic/claude-opus-4-6"); + expect(config?.model).toBe("anthropic/claude-opus-4-7"); expect(config?.permission).toHaveProperty("apply_patch", "allow"); }); }); diff --git a/src/agents/hephaestus/gpt-5-3-codex.ts b/src/agents/hephaestus/gpt-5-3-codex.ts index 2ca2964f7..28127bcc8 100644 --- a/src/agents/hephaestus/gpt-5-3-codex.ts +++ b/src/agents/hephaestus/gpt-5-3-codex.ts @@ -409,9 +409,9 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU Every \`task()\` output includes a session_id. **USE IT for follow-ups.** -- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` -- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` -- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` +- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\` +- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\` +- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\` ${ oracleSection diff --git a/src/agents/hephaestus/gpt-5-4.ts b/src/agents/hephaestus/gpt-5-4.ts index a88b6ea0f..eec4e18b4 100644 --- a/src/agents/hephaestus/gpt-5-4.ts +++ b/src/agents/hephaestus/gpt-5-4.ts @@ -312,10 +312,10 @@ Every delegation prompt needs these 6 sections: After delegation, verify by reading every file the subagent touched. Check: works as expected? follows codebase pattern? Do not trust self-reports. -Every \`task()\` returns a session_id. Use it for all follow-ups: -- Task failed/incomplete: \`session_id="{id}", prompt="Fix: {error}"\` -- Follow-up on result: \`session_id="{id}", prompt="Also: {question}"\` -- Verification failed: \`session_id="{id}", prompt="Failed: {error}. Fix."\` +Every \`task()\` returns a task_id. Use it for all follow-ups: +- Task failed/incomplete: \`task_id="{id}", prompt="Fix: {error}"\` +- Follow-up on result: \`task_id="{id}", prompt="Also: {question}"\` +- Verification failed: \`task_id="{id}", prompt="Failed: {error}. Fix."\` This preserves full context, avoids repeated exploration, saves 70%+ tokens. diff --git a/src/agents/hephaestus/gpt.ts b/src/agents/hephaestus/gpt.ts index cf1a3ea91..712bb9536 100644 --- a/src/agents/hephaestus/gpt.ts +++ b/src/agents/hephaestus/gpt.ts @@ -277,11 +277,11 @@ After delegation, ALWAYS verify: works as expected? follows codebase pattern? MU ### Session Continuity -Every \`task()\` output includes a session_id. **USE IT for follow-ups.** +Every \`task()\` output includes a task_id. **USE IT for follow-ups.** -- **Task failed/incomplete** - \`session_id="{id}", prompt="Fix: {error}"\` -- **Follow-up on result** - \`session_id="{id}", prompt="Also: {question}"\` -- **Verification failed** - \`session_id="{id}", prompt="Failed: {error}. Fix."\` +- **Task failed/incomplete** - \`task_id="{id}", prompt="Fix: {error}"\` +- **Follow-up on result** - \`task_id="{id}", prompt="Also: {question}"\` +- **Verification failed** - \`task_id="{id}", prompt="Failed: {error}. Fix."\` ${ oracleSection diff --git a/src/agents/sisyphus.ts b/src/agents/sisyphus.ts index 55b6c1c21..81a863d54 100644 --- a/src/agents/sisyphus.ts +++ b/src/agents/sisyphus.ts @@ -317,15 +317,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING: ### Session Continuity (MANDATORY) -Every \`task()\` output includes a session_id. **USE IT.** +Every \`task()\` output includes a task_id. **USE IT.** **ALWAYS continue when:** -- Task failed/incomplete → \`session_id=\"{session_id}\", prompt=\"Fix: {specific error}\"\` -- Follow-up question on result → \`session_id=\"{session_id}\", prompt=\"Also: {question}\"\` -- Multi-turn with same agent → \`session_id=\"{session_id}\"\` - NEVER start fresh -- Verification failed → \`session_id=\"{session_id}\", prompt=\"Failed verification: {error}. Fix.\"\` +- Task failed/incomplete → \`task_id=\"{task_id}\", prompt=\"Fix: {specific error}\"\` +- Follow-up question on result → \`task_id=\"{task_id}\", prompt=\"Also: {question}\"\` +- Multi-turn with same agent → \`task_id=\"{task_id}\"\` - NEVER start fresh +- Verification failed → \`task_id=\"{task_id}\", prompt=\"Failed verification: {error}. Fix.\"\` -**Why session_id is CRITICAL:** +**Why task_id is CRITICAL:** - Subagent has FULL conversation context preserved - No repeated file reads, exploration, or setup - Saves 70%+ tokens on follow-ups @@ -336,10 +336,10 @@ Every \`task()\` output includes a session_id. **USE IT.** task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") // CORRECT: Resume preserves everything -task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") +task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") \`\`\` -**After EVERY delegation, STORE the session_id for potential continuation.** +**After EVERY delegation, STORE the task_id for potential continuation.** ### Code Changes: - Match existing patterns (if codebase is disciplined) diff --git a/src/agents/sisyphus/default.ts b/src/agents/sisyphus/default.ts index 14895b124..52e237f7c 100644 --- a/src/agents/sisyphus/default.ts +++ b/src/agents/sisyphus/default.ts @@ -389,15 +389,15 @@ AFTER THE WORK YOU DELEGATED SEEMS DONE, ALWAYS VERIFY THE RESULTS AS FOLLOWING: ### Session Continuity (MANDATORY) -Every \`task()\` output includes a session_id. **USE IT.** +Every \`task()\` output includes a task_id. **USE IT.** **ALWAYS continue when:** -- Task failed/incomplete → \`session_id="{session_id}", prompt="Fix: {specific error}"\` -- Follow-up question on result → \`session_id="{session_id}", prompt="Also: {question}"\` -- Multi-turn with same agent → \`session_id="{session_id}"\` - NEVER start fresh -- Verification failed → \`session_id="{session_id}", prompt="Failed verification: {error}. Fix."\` +- Task failed/incomplete → \`task_id="{task_id}", prompt="Fix: {specific error}"\` +- Follow-up question on result → \`task_id="{task_id}", prompt="Also: {question}"\` +- Multi-turn with same agent → \`task_id="{task_id}"\` - NEVER start fresh +- Verification failed → \`task_id="{task_id}", prompt="Failed verification: {error}. Fix."\` -**Why session_id is CRITICAL:** +**Why task_id is CRITICAL:** - Subagent has FULL conversation context preserved - No repeated file reads, exploration, or setup - Saves 70%+ tokens on follow-ups @@ -408,10 +408,10 @@ Every \`task()\` output includes a session_id. **USE IT.** task(category="quick", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix the type error in auth.ts...") // CORRECT: Resume preserves everything -task(session_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") +task(task_id="ses_abc123", load_skills=[], run_in_background=false, description="Fix type error", prompt="Fix: Type error on line 42") \`\`\` -**After EVERY delegation, STORE the session_id for potential continuation.** +**After EVERY delegation, STORE the task_id for potential continuation.** ### Code Changes: - Match existing patterns (if codebase is disciplined) diff --git a/src/agents/sisyphus/gpt-5-4.ts b/src/agents/sisyphus/gpt-5-4.ts index 9e8219015..4667e3466 100644 --- a/src/agents/sisyphus/gpt-5-4.ts +++ b/src/agents/sisyphus/gpt-5-4.ts @@ -387,10 +387,10 @@ Post-delegation: delegation never substitutes for verification. Always run \` { }); test("does not match non-GPT models", () => { - expect(isGpt5_4Model("anthropic/claude-opus-4-6")).toBe(false); + expect(isGpt5_4Model("anthropic/claude-opus-4-7")).toBe(false); expect(isGpt5_4Model("google/gemini-3.1-pro")).toBe(false); expect(isGpt5_4Model("openai/o1")).toBe(false); }); @@ -64,7 +64,7 @@ describe("isGptModel", () => { }); test("claude models are not gpt", () => { - expect(isGptModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGptModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGptModel("anthropic/claude-sonnet-4-6")).toBe(false); expect(isGptModel("litellm/anthropic.claude-opus-4-5")).toBe(false); }); @@ -75,7 +75,7 @@ describe("isGptModel", () => { }); test("opencode provider is not gpt", () => { - expect(isGptModel("opencode/claude-opus-4-6")).toBe(false); + expect(isGptModel("opencode/claude-opus-4-7")).toBe(false); }); }); @@ -95,7 +95,7 @@ describe("isMiniMaxModel", () => { 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("anthropic/claude-opus-4-7")).toBe(false); expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false); expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false); }); @@ -116,7 +116,7 @@ describe("isGlmModel", () => { test("#given non-GLM models #then returns false", () => { expect(isGlmModel("openai/gpt-5.4")).toBe(false); - expect(isGlmModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGlmModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGlmModel("google/gemini-3.1-pro")).toBe(false); }); }); @@ -156,11 +156,11 @@ describe("isGeminiModel", () => { }); test("#given claude models #then returns false", () => { - expect(isGeminiModel("anthropic/claude-opus-4-6")).toBe(false); + expect(isGeminiModel("anthropic/claude-opus-4-7")).toBe(false); expect(isGeminiModel("anthropic/claude-sonnet-4-6")).toBe(false); }); test("#given opencode provider #then returns false", () => { - expect(isGeminiModel("opencode/claude-opus-4-6")).toBe(false); + expect(isGeminiModel("opencode/claude-opus-4-7")).toBe(false); }); }); diff --git a/src/agents/utils.test.ts b/src/agents/utils.test.ts index b63a34827..bd8bb5740 100644 --- a/src/agents/utils.test.ts +++ b/src/agents/utils.test.ts @@ -7,7 +7,7 @@ import * as connectedProvidersCache from "../shared/connected-providers-cache" import * as modelAvailability from "../shared/model-availability" import * as shared from "../shared" -const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-6" +const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-7" let createBuiltinAgents: (typeof import("./builtin-agents"))["createBuiltinAgents"] async function importFreshBuiltinAgentsModule(): Promise { @@ -32,7 +32,7 @@ describe("createBuiltinAgents with model overrides", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -45,7 +45,7 @@ describe("createBuiltinAgents with model overrides", () => { const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL, undefined, undefined, [], {}) // #then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 }) expect(agents.sisyphus.reasoningEffort).toBeUndefined() } finally { @@ -170,7 +170,7 @@ describe("createBuiltinAgents with model overrides", () => { test("Sisyphus is created on first run when no availableModels or cache exist", async () => { // #given - const systemDefaultModel = "anthropic/claude-opus-4-6" + const systemDefaultModel = "anthropic/claude-opus-4-7" const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) @@ -180,7 +180,7 @@ describe("createBuiltinAgents with model overrides", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -299,7 +299,7 @@ describe("createBuiltinAgents with model overrides", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -341,7 +341,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes hidden custom agents from orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -377,7 +377,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes disabled custom agents from orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -413,7 +413,7 @@ describe("createBuiltinAgents with model overrides", () => { test("excludes custom agents when disabledAgents contains their name (case-insensitive)", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const disabledAgents = ["ReSeArChEr"] @@ -449,7 +449,7 @@ describe("createBuiltinAgents with model overrides", () => { test("does not advertise duplicate custom agents case-insensitively", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -481,7 +481,7 @@ describe("createBuiltinAgents with model overrides", () => { test("does not surface custom agent strings in orchestrator prompts", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) const customAgentSummaries = [ @@ -555,7 +555,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => { ]) const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "kimi-for-coding/k2p5", "opencode/kimi-k2.5-free", "zai-coding-plan/glm-5", @@ -569,7 +569,7 @@ describe("createBuiltinAgents without systemDefaultModel", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -590,7 +590,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => const providers = options?.connectedProviders ?? [] return providers.includes("openai") ? new Set(["openai/gpt-5.3-codex"]) - : new Set(["anthropic/claude-opus-4-6"]) + : new Set(["anthropic/claude-opus-4-7"]) }) try { @@ -609,7 +609,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => test("hephaestus is not created when no required provider is connected", async () => { // #given - only anthropic models available, not in hephaestus requiresProvider const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"]) @@ -699,10 +699,10 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () => test("hephaestus is created when explicit config provided even if provider unavailable", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) const overrides = { - hephaestus: { model: "anthropic/claude-opus-4-6" }, + hephaestus: { model: "anthropic/claude-opus-4-7" }, } try { @@ -781,7 +781,7 @@ describe("Sisyphus and Librarian environment context toggle", () => { beforeEach(() => { fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "google/gemini-3-flash"]) + new Set(["anthropic/claude-opus-4-7", "google/gemini-3-flash"]) ) }) @@ -840,7 +840,7 @@ describe("Atlas is unaffected by environment context toggle", () => { beforeEach(() => { fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6", "openai/gpt-5.4"]) + new Set(["anthropic/claude-opus-4-7", "openai/gpt-5.4"]) ) }) @@ -893,7 +893,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { test("sisyphus is created when at least one fallback model is available", async () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue( - new Set(["anthropic/claude-opus-4-6"]) + new Set(["anthropic/claude-opus-4-7"]) ) try { @@ -918,7 +918,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { // #then expect(agents.sisyphus).toBeDefined() - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.7") } finally { cacheSpy.mockRestore() fetchSpy.mockRestore() @@ -929,7 +929,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { // #given const fetchSpy = spyOn(shared, "fetchAvailableModels").mockResolvedValue(new Set()) const overrides = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, } try { @@ -1039,7 +1039,7 @@ describe("createBuiltinAgents with requiresAnyModel gating (sisyphus)", () => { describe("buildAgent with category and skills", () => { const { buildAgent } = require("./agent-builder") - const TEST_MODEL = "anthropic/claude-opus-4-6" + const TEST_MODEL = "anthropic/claude-opus-4-7" beforeEach(() => { clearSkillCache() diff --git a/src/cli/AGENTS.md b/src/cli/AGENTS.md index 7ac648408..47b61eb49 100644 --- a/src/cli/AGENTS.md +++ b/src/cli/AGENTS.md @@ -1,6 +1,6 @@ # src/cli/ — CLI: install, run, doctor, mcp-oauth -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/cli/__snapshots__/model-fallback.test.ts.snap b/src/cli/__snapshots__/model-fallback.test.ts.snap index 88f86f97b..ddc9a60a0 100644 --- a/src/cli/__snapshots__/model-fallback.test.ts.snap +++ b/src/cli/__snapshots__/model-fallback.test.ts.snap @@ -69,67 +69,62 @@ exports[`generateModelConfig single native provider uses Claude models when only "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -140,68 +135,63 @@ exports[`generateModelConfig single native provider uses Claude models with isMa "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "opencode/gpt-5-nano", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -216,16 +206,14 @@ exports[`generateModelConfig single native provider uses OpenAI models when only "variant": "medium", }, "explore": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "model": "openai/gpt-5.4", @@ -306,16 +294,14 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa "variant": "medium", }, "explore": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, "librarian": { - "model": "openai/gpt-5.4", - "variant": "medium", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "model": "openai/gpt-5.4", @@ -526,20 +512,34 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -547,13 +547,13 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -580,7 +580,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -597,7 +597,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -607,7 +607,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -617,14 +617,14 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -637,7 +637,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -651,7 +651,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "google/gemini-3-flash-preview", @@ -666,7 +666,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -683,7 +683,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -695,12 +695,12 @@ exports[`generateModelConfig all native providers uses preferred models from fal "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -710,7 +710,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -730,20 +730,34 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "anthropic/claude-haiku-4-5", + }, + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -751,13 +765,13 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -784,7 +798,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -801,7 +815,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -811,7 +825,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -821,14 +835,14 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -841,7 +855,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { @@ -855,7 +869,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "google/gemini-3-flash-preview", @@ -870,7 +884,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -884,7 +898,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -897,12 +911,12 @@ exports[`generateModelConfig all native providers uses preferred models with isM "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -912,7 +926,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -937,10 +951,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -956,13 +967,13 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -989,7 +1000,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1006,7 +1017,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/gemini-3.1-pro", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -1025,7 +1036,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/big-pickle", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -1045,7 +1056,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "artistry": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1058,7 +1069,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "deep": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1090,7 +1101,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1127,7 +1138,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on "model": "opencode/glm-5", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1162,10 +1173,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "explore": { "fallback_models": [ { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -1181,13 +1189,13 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1214,7 +1222,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1231,7 +1239,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/gemini-3.1-pro", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -1250,7 +1258,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/big-pickle", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -1270,7 +1278,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "artistry": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1283,7 +1291,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "deep": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1315,7 +1323,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "variant": "high", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1335,7 +1343,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/kimi-k2.5", }, ], - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -1356,7 +1364,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is "model": "opencode/glm-5", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1389,11 +1397,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1407,13 +1410,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1434,7 +1437,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1451,7 +1454,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -1461,7 +1464,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -1478,7 +1481,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1491,7 +1494,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "deep": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1516,7 +1519,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "ultrabrain": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1542,7 +1545,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1575,11 +1578,6 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "model": "github-copilot/claude-sonnet-4.6", }, "explore": { - "fallback_models": [ - { - "model": "github-copilot/grok-code-fast-1", - }, - ], "model": "github-copilot/gpt-5-mini", }, "hephaestus": { @@ -1593,13 +1591,13 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1620,7 +1618,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1637,7 +1635,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -1647,7 +1645,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -1664,7 +1662,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1677,7 +1675,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "deep": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -1702,7 +1700,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "ultrabrain": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1716,7 +1714,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "unspecified-low": { @@ -1730,7 +1728,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -1885,21 +1883,15 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "anthropic/claude-haiku-4.5", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "anthropic/claude-haiku-4-5", @@ -1911,7 +1903,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "metis": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1919,17 +1911,17 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1956,11 +1948,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -1970,7 +1962,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "prometheus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -1981,13 +1973,13 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2004,7 +1996,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -2020,18 +2012,18 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2044,11 +2036,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "deep": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2062,7 +2054,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "quick": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", @@ -2083,11 +2075,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2107,7 +2099,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -2122,7 +2114,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -2130,11 +2122,11 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2144,7 +2136,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "opencode/claude-sonnet-4-6", @@ -2176,10 +2168,10 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", + "model": "openai/gpt-5.4-nano", }, ], - "model": "github-copilot/gpt-5-mini", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -2191,6 +2183,14 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "openai/gpt-5.4", "variant": "medium", }, + "librarian": { + "fallback_models": [ + { + "model": "openai/gpt-5.4-nano", + }, + ], + "model": "openai/gpt-5.4-mini-fast", + }, "metis": { "fallback_models": [ { @@ -2202,7 +2202,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { @@ -2212,7 +2212,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "xhigh", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2246,7 +2246,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2267,7 +2267,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "model": "github-copilot/gemini-3.1-pro-preview", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -2281,7 +2281,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "medium", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -2302,7 +2302,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "artistry": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2322,7 +2322,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "medium", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { @@ -2354,7 +2354,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2388,7 +2388,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb "visual-engineering": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, ], @@ -2412,41 +2412,36 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "librarian": { "fallback_models": [ { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, ], "model": "zai-coding-plan/glm-4.7", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { "model": "zai-coding-plan/glm-4.6v", }, "oracle": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "prometheus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { @@ -2455,42 +2450,42 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + ZAI combinat "model": "zai-coding-plan/glm-5", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "deep": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-high": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], "model": "zai-coding-plan/glm-5", }, "writing": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, } @@ -2501,18 +2496,13 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "agents": { "atlas": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { - "fallback_models": [ - { - "model": "anthropic/claude-haiku-4.5", - }, - ], "model": "anthropic/claude-haiku-4-5", }, "metis": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -2522,7 +2512,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "multimodal-looker": { @@ -2531,7 +2521,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "oracle": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2544,22 +2534,22 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3.1-pro-preview", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { "artistry": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2573,7 +2563,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "quick": { @@ -2582,12 +2572,12 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, "ultrabrain": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2600,7 +2590,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -2608,12 +2598,12 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "model": "google/gemini-3-flash-preview", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, ], @@ -2623,7 +2613,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi "writing": { "fallback_models": [ { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, ], "model": "google/gemini-3-flash-preview", @@ -2655,13 +2645,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "opencode/claude-haiku-4-5", @@ -2678,14 +2662,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider }, "librarian": { "fallback_models": [ - { - "model": "opencode/minimax-m2.7-highspeed", - }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "opencode/gpt-5.4-nano", }, ], "model": "zai-coding-plan/glm-4.7", @@ -2693,7 +2674,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "metis": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2705,7 +2686,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "momus": { @@ -2715,11 +2696,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "xhigh", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2764,11 +2745,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2778,7 +2759,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "prometheus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2796,13 +2777,13 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/gemini-3.1-pro", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2826,7 +2807,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/big-pickle", }, ], - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -2857,11 +2838,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2881,11 +2862,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "medium", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -2934,11 +2915,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "variant": "high", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -2994,11 +2975,11 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider "model": "opencode/glm-5", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3048,27 +3029,24 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3087,28 +3065,28 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "librarian": { "fallback_models": [ { - "model": "opencode/minimax-m2.7-highspeed", - }, - { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3124,7 +3102,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -3138,15 +3116,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3210,15 +3188,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3228,11 +3206,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3257,17 +3235,17 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3295,7 +3273,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -3322,7 +3300,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { @@ -3337,15 +3315,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3372,15 +3350,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "medium", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3408,7 +3386,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gpt-5.4-mini", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "github-copilot/claude-haiku-4.5", @@ -3450,15 +3428,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3491,7 +3469,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "unspecified-low": { "fallback_models": [ @@ -3519,7 +3497,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -3538,15 +3516,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3562,7 +3540,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe "model": "opencode/gemini-3-flash", }, { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "github-copilot/claude-sonnet-4.6", @@ -3602,27 +3580,24 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "medium", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "explore": { "fallback_models": [ { - "model": "github-copilot/grok-code-fast-1", - }, - { - "model": "opencode/minimax-m2.7", - }, - { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "anthropic/claude-haiku-4-5", + "model": "openai/gpt-5.4-mini-fast", }, "hephaestus": { "fallback_models": [ @@ -3641,28 +3616,28 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "librarian": { "fallback_models": [ { - "model": "opencode/minimax-m2.7-highspeed", - }, - { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "opencode/claude-haiku-4-5", }, { - "model": "opencode/gpt-5-nano", + "model": "openai/gpt-5.4-nano", + }, + { + "model": "opencode/gpt-5.4-nano", }, ], - "model": "zai-coding-plan/glm-4.7", + "model": "openai/gpt-5.4-mini-fast", }, "metis": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3678,7 +3653,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "momus": { @@ -3692,15 +3667,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "xhigh", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3764,15 +3739,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -3782,11 +3757,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "prometheus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3811,17 +3786,17 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3.1-pro", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3849,7 +3824,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "sisyphus-junior": { @@ -3876,7 +3851,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/big-pickle", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, }, "categories": { @@ -3891,15 +3866,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3926,15 +3901,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "medium", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -3962,7 +3937,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gpt-5.4-mini", }, { - "model": "anthropic/claude-haiku-4.5", + "model": "anthropic/claude-haiku-4-5", }, { "model": "github-copilot/claude-haiku-4.5", @@ -4004,15 +3979,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "variant": "high", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -4022,11 +3997,11 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "unspecified-high": { "fallback_models": [ { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, { @@ -4051,7 +4026,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/kimi-k2.5", }, ], - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, "unspecified-low": { @@ -4080,7 +4055,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3-flash", }, ], - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, "visual-engineering": { "fallback_models": [ @@ -4099,15 +4074,15 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/glm-5", }, { - "model": "anthropic/claude-opus-4.6", + "model": "anthropic/claude-opus-4-7", "variant": "max", }, { - "model": "github-copilot/claude-opus-4.6", + "model": "github-copilot/claude-opus-4.7", "variant": "max", }, { - "model": "opencode/claude-opus-4-6", + "model": "opencode/claude-opus-4-7", "variant": "max", }, ], @@ -4123,7 +4098,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is "model": "opencode/gemini-3-flash", }, { - "model": "anthropic/claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4-6", }, { "model": "github-copilot/claude-sonnet-4.6", @@ -4159,9 +4134,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4169,7 +4141,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4187,7 +4159,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", @@ -4202,13 +4174,13 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4244,7 +4216,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4267,7 +4239,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/google/gemini-3.1-pro-preview", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -4283,7 +4255,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -4306,7 +4278,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "artistry": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4319,7 +4291,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "deep": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4354,7 +4326,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4406,7 +4378,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, ], @@ -4452,9 +4424,6 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin }, "explore": { "fallback_models": [ - { - "model": "vercel/xai/grok-code-fast-1", - }, { "model": "vercel/minimax/minimax-m2.7", }, @@ -4462,7 +4431,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7-highspeed", @@ -4480,7 +4449,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/anthropic/claude-haiku-4.5", }, { - "model": "vercel/openai/gpt-5-nano", + "model": "vercel/openai/gpt-5.4-nano", }, ], "model": "vercel/minimax/minimax-m2.7", @@ -4495,13 +4464,13 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "momus": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4537,7 +4506,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4560,7 +4529,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/google/gemini-3.1-pro-preview", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus": { @@ -4576,7 +4545,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "sisyphus-junior": { @@ -4599,7 +4568,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "artistry": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4612,7 +4581,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "deep": { "fallback_models": [ { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4647,7 +4616,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "variant": "high", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, { @@ -4670,7 +4639,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/moonshotai/kimi-k2.5", }, ], - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, "unspecified-low": { @@ -4697,7 +4666,7 @@ exports[`generateModelConfig Vercel AI Gateway provider uses vercel/ model strin "model": "vercel/zai/glm-5", }, { - "model": "vercel/anthropic/claude-opus-4.6", + "model": "vercel/anthropic/claude-opus-4.7", "variant": "max", }, ], diff --git a/src/cli/cli-program.ts b/src/cli/cli-program.ts index 6d982e57b..4835495a5 100644 --- a/src/cli/cli-program.ts +++ b/src/cli/cli-program.ts @@ -46,7 +46,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi > Verce OpenAI Native openai/ models (GPT-5.4 for Oracle) Gemini Native google/ models (Gemini 3.1 Pro, Flash) Copilot github-copilot/ models (fallback) - OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.) + OpenCode Zen opencode/ models (opencode/claude-opus-4-7, etc.) Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback) Vercel vercel/ models (universal proxy, always last fallback) diff --git a/src/cli/config-manager/generate-omo-config.test.ts b/src/cli/config-manager/generate-omo-config.test.ts index 50fe4e3d8..8b4a1dde1 100644 --- a/src/cli/config-manager/generate-omo-config.test.ts +++ b/src/cli/config-manager/generate-omo-config.test.ts @@ -26,8 +26,8 @@ describe("generateOmoConfig - model fallback system", () => { //#then expect([ - "github-copilot/claude-opus-4.6", - "github-copilot/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "github-copilot/claude-opus-4-7", ]).toContain((result.agents as Record).sisyphus.model) }) @@ -74,7 +74,7 @@ describe("generateOmoConfig - model fallback system", () => { //#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") + expect((result.agents as Record).sisyphus.model).toBe("anthropic/claude-opus-4-7") }) test("uses native OpenAI models when only ChatGPT available", () => { @@ -131,7 +131,7 @@ describe("generateOmoConfig - model fallback system", () => { }> //#then - expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4.6") + expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-7") expect(agents.sisyphus.fallback_models).toEqual([ { model: "openai/gpt-5.4", @@ -141,7 +141,7 @@ describe("generateOmoConfig - model fallback system", () => { expect(categories.deep.model).toBe("openai/gpt-5.4") expect(categories.deep.fallback_models).toEqual([ { - model: "anthropic/claude-opus-4.6", + model: "anthropic/claude-opus-4-7", variant: "max", }, ]) diff --git a/src/cli/doctor/AGENTS.md b/src/cli/doctor/AGENTS.md new file mode 100644 index 000000000..5ba601afe --- /dev/null +++ b/src/cli/doctor/AGENTS.md @@ -0,0 +1,82 @@ +# src/cli/doctor/ — Health Diagnostics (25 Check Files) + +**Generated:** 2026-04-18 + +## OVERVIEW + +`bunx oh-my-opencode doctor` — parallel diagnostic checks across 4 categories (System, Config, Tools, Models). Catches broken installs, config typos, missing dependencies, provider misconfigurations before they become runtime errors. + +## COMMAND FLAGS + +```bash +bunx oh-my-opencode doctor # Full diagnostics (all 4 categories) +bunx oh-my-opencode doctor --status # Compact dashboard (status only) +bunx oh-my-opencode doctor --verbose # Deep details (model resolution traces) +bunx oh-my-opencode doctor --json # Machine-readable output +``` + +## CHECK CATEGORIES + +| Category | File | Validates | +|----------|------|-----------| +| **SYSTEM** | `checks/system.ts` | OpenCode binary found + version ≥1.0.150, plugin registered in opencode.json, loaded plugin version matches installed | +| **CONFIG** | `checks/config.ts` | JSONC validity, Zod schema passes, no unknown keys, model override syntax correct | +| **TOOLS** | `checks/tools.ts` | AST-Grep CLI + NAPI, comment-checker binary, LSP servers reachable, GitHub CLI auth, built-in MCP reachability | +| **MODELS** | `checks/model-resolution.ts` | models.json cache exists, per-agent fallback resolution, category overrides valid, provider availability | + +## SUPPORTING CHECK FILES (25 total) + +``` +checks/ +├── index.ts # Registration +├── system.ts # Main System aggregator +├── system-binary.ts # OpenCode binary discovery (PATH + desktop app) +├── system-plugin.ts # opencode.json plugin entry detection +├── system-loaded-version.ts # Cache vs npm latest +├── config.ts # Main Config aggregator +├── tools.ts # Main Tools aggregator +├── dependencies.ts # AST-Grep CLI/NAPI + comment-checker presence +├── tools-gh.ts # gh cli install + auth status +├── tools-lsp.ts # LSP server enumeration +├── tools-mcp.ts # Built-in + user MCP reachability +├── model-resolution.ts # Main Models aggregator +├── model-resolution-cache.ts # models.json presence + freshness +├── model-resolution-config.ts # oh-my-opencode.jsonc parse +├── model-resolution-effective-model.ts # Per-agent fallback chain trace +├── model-resolution-variant.ts # Model variant (max, high, medium) handling +├── model-resolution-details.ts # Verbose output formatter +└── model-resolution-types.ts # Shared types +``` + +## EXECUTION FLOW + +``` +doctor command + → runner.ts: parallel check execution with 30s per-check timeout + → checks/index.ts registers all 4 category checks + → each check returns: { status: "ok" | "warn" | "error", detail: string } + → formatter.ts: render to stdout (text/status/json) + → exit code: 0 (all ok) | 1 (errors) | 2 (warnings only) +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | CLI command entry, flag parsing | +| `runner.ts` | Parallel `Promise.allSettled()` orchestration, 30s timeout per check | +| `formatter.ts` | Pretty printing: colored status, hierarchical output | +| `types.ts` | `DoctorCheck`, `CheckResult`, `DoctorReport` types | + +## HOW TO ADD A CHECK + +1. Create `src/cli/doctor/checks/{name}.ts` exporting check function matching `DoctorCheck` +2. Register in `checks/index.ts` +3. Category-level aggregator (system/config/tools/model-resolution) invokes it +4. Return `{ status, detail }` — no throws, all errors caught by runner + +## EXIT CODES + +- `0`: All checks passed (or only info messages) +- `1`: One or more errors — plugin will likely not work +- `2`: Warnings only — plugin works with degraded features diff --git a/src/cli/doctor/checks/model-resolution-cache.test.ts b/src/cli/doctor/checks/model-resolution-cache.test.ts index df6d68f16..58b0ce3d4 100644 --- a/src/cli/doctor/checks/model-resolution-cache.test.ts +++ b/src/cli/doctor/checks/model-resolution-cache.test.ts @@ -34,7 +34,7 @@ describe("loadAvailableModelsFromCache", () => { join(tempDir, "cache", "opencode", "models.json"), JSON.stringify({ openai: { models: { "gpt-5.4": {} } }, - anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } }, + anthropic: { models: { "claude-opus-4-7": {}, "claude-sonnet-4-6": {} } }, }) ) diff --git a/src/cli/doctor/checks/model-resolution.test.ts b/src/cli/doctor/checks/model-resolution.test.ts index b64b1fa10..2d1c09919 100644 --- a/src/cli/doctor/checks/model-resolution.test.ts +++ b/src/cli/doctor/checks/model-resolution.test.ts @@ -14,7 +14,7 @@ describe("model-resolution check", () => { // then: Should have agent entries const sisyphus = info.agents.find((a) => a.name === "sisyphus") expect(sisyphus).toBeDefined() - expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-6") + expect(sisyphus!.requirement.fallbackChain[0]?.model).toBe("claude-opus-4-7") expect(sisyphus!.requirement.fallbackChain[0]?.providers).toContain("anthropic") }) @@ -42,7 +42,7 @@ describe("model-resolution check", () => { // given: User has override for oracle agent const mockConfig = { agents: { - oracle: { model: "anthropic/claude-opus-4-6" }, + oracle: { model: "anthropic/claude-opus-4-7" }, }, } @@ -51,8 +51,8 @@ describe("model-resolution check", () => { // then: Oracle should show the override const oracle = info.agents.find((a) => a.name === "oracle") expect(oracle).toBeDefined() - expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-6") - expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-6") + expect(oracle!.userOverride).toBe("anthropic/claude-opus-4-7") + expect(oracle!.effectiveResolution).toBe("User override: anthropic/claude-opus-4-7") }) it("shows user override for category when configured", async () => { @@ -169,13 +169,13 @@ describe("model-resolution check", () => { const info = getModelResolutionInfoWithOverrides({ agents: { - oracle: { model: "anthropic/claude-opus-4-6-thinking" }, + oracle: { model: "anthropic/claude-opus-4-7-thinking" }, }, }) const oracle = info.agents.find((agent) => agent.name === "oracle") expect(oracle).toBeDefined() - expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-6-thinking") + expect(oracle!.effectiveModel).toBe("anthropic/claude-opus-4-7-thinking") expect(oracle!.capabilityDiagnostics).toMatchObject({ resolutionMode: "alias-backed", canonicalization: { diff --git a/src/cli/model-fallback.test.ts b/src/cli/model-fallback.test.ts index f1df3cc0a..ec27d40c6 100644 --- a/src/cli/model-fallback.test.ts +++ b/src/cli/model-fallback.test.ts @@ -355,9 +355,9 @@ describe("generateModelConfig", () => { // #when generateModelConfig is called const result = generateModelConfig(config) - // #then explore should use native OpenAI model - expect(result.agents?.explore?.model).toBe("openai/gpt-5.4") - expect(result.agents?.explore?.variant).toBe("medium") + // #then explore should use native OpenAI mini-fast (primary model) + expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast") + expect(result.agents?.explore?.variant).toBeUndefined() }) test("explore uses gpt-5-mini when only Copilot available", () => { @@ -381,7 +381,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) test("Sisyphus is created when multiple fallback providers are available", () => { @@ -398,7 +398,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) test("Sisyphus resolves to gpt-5.4 medium when only OpenAI is available", () => { @@ -553,15 +553,15 @@ describe("generateModelConfig", () => { }) describe("special-case agents include fallback_models", () => { - test("explore includes fallback_models when Copilot and Claude are both available", () => { - // #given both Copilot and Claude are available - const config = createConfig({ hasCopilot: true, hasClaude: true }) + test("explore includes fallback_models when OpenAI and Claude are both available", () => { + // #given both OpenAI and Claude are available + const config = createConfig({ hasOpenAI: true, hasClaude: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then explore should have fallback_models from the remaining chain entries - expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") + expect(result.agents?.explore?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.explore?.fallback_models).toBeDefined() expect(result.agents?.explore?.fallback_models?.length).toBeGreaterThan(0) }) @@ -573,37 +573,33 @@ describe("generateModelConfig", () => { // #when generateModelConfig is called const result = generateModelConfig(config) - // #then explore should not have fallback_models (only one chain entry matches) + // #then explore should not have fallback_models (only one distinct chain entry matches) expect(result.agents?.explore?.model).toBe("anthropic/claude-haiku-4-5") - expect(result.agents?.explore?.fallback_models).toEqual([ - { - model: "anthropic/claude-haiku-4.5", - }, - ]) + expect(result.agents?.explore?.fallback_models).toBeUndefined() }) - test("librarian includes fallback_models when opencode-go and Claude are both available", () => { - // #given opencode-go and Claude are available - const config = createConfig({ hasOpencodeGo: true, hasClaude: true }) + test("librarian includes fallback_models when OpenAI and opencode-go are both available", () => { + // #given OpenAI and opencode-go are available + const config = createConfig({ hasOpenAI: true, hasOpencodeGo: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("openai/gpt-5.4-mini-fast") expect(result.agents?.librarian?.fallback_models).toBeDefined() expect(result.agents?.librarian?.fallback_models?.length).toBeGreaterThan(0) }) - test("librarian omits fallback_models when only one provider matches", () => { - // #given only opencode-go is available - const config = createConfig({ hasOpencodeGo: true }) + test("librarian omits fallback_models when only ZAI is available", () => { + // #given only ZAI is available + const config = createConfig({ hasZaiCodingPlan: true }) // #when generateModelConfig is called const result = generateModelConfig(config) // #then librarian should not have fallback_models - expect(result.agents?.librarian?.model).toBe("opencode-go/minimax-m2.7") + expect(result.agents?.librarian?.model).toBe("zai-coding-plan/glm-4.7") expect(result.agents?.librarian?.fallback_models).toBeUndefined() }) }) @@ -672,7 +668,7 @@ describe("generateModelConfig", () => { const result = generateModelConfig(config) // #then should prefer native anthropic over gateway - expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4.6") + expect(result.agents?.sisyphus?.model).toBe("anthropic/claude-opus-4-7") }) }) diff --git a/src/cli/model-fallback.ts b/src/cli/model-fallback.ts index 088c4515e..6378482c6 100644 --- a/src/cli/model-fallback.ts +++ b/src/cli/model-fallback.ts @@ -127,7 +127,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) { if (role === "librarian") { let agentConfig: AgentConfig | undefined - if (avail.opencodeGo) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.opencodeGo) { agentConfig = { model: "opencode-go/minimax-m2.7" } } else if (avail.zai) { agentConfig = { model: ZAI_MODEL } @@ -142,7 +144,9 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig { if (role === "explore") { let agentConfig: AgentConfig - if (avail.native.claude) { + if (avail.native.openai) { + agentConfig = { model: "openai/gpt-5.4-mini-fast" } + } else if (avail.native.claude) { agentConfig = { model: "anthropic/claude-haiku-4-5" } } else if (avail.opencodeZen) { agentConfig = { model: "opencode/claude-haiku-4-5" } diff --git a/src/cli/openai-only-model-catalog.test.ts b/src/cli/openai-only-model-catalog.test.ts index da544156c..7c94aa850 100644 --- a/src/cli/openai-only-model-catalog.test.ts +++ b/src/cli/openai-only-model-catalog.test.ts @@ -28,8 +28,8 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) - expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4", variant: "medium" }) + expect(result.agents?.explore).toEqual({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.librarian).toEqual({ model: "openai/gpt-5.4-mini-fast" }) }) test("fills remaining OpenAI-only category gaps with OpenAI models", () => { @@ -54,8 +54,10 @@ describe("generateModelConfig OpenAI-only model catalog", () => { const result = generateModelConfig(config) // #then - expect(result.agents?.explore).toMatchObject({ model: "opencode-go/minimax-m2.7" }) - expect(result.agents?.librarian).toMatchObject({ model: "opencode-go/minimax-m2.7" }) + expect(result.agents?.explore).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.librarian).toMatchObject({ model: "openai/gpt-5.4-mini-fast" }) + expect(result.agents?.explore).not.toMatchObject({ variant: "medium" }) + expect(result.agents?.librarian).not.toMatchObject({ variant: "medium" }) expect(result.categories?.quick).toMatchObject({ model: "openai/gpt-5.4-mini" }) }) }) diff --git a/src/cli/openai-only-model-catalog.ts b/src/cli/openai-only-model-catalog.ts index 186b600b2..36d6ca802 100644 --- a/src/cli/openai-only-model-catalog.ts +++ b/src/cli/openai-only-model-catalog.ts @@ -1,8 +1,8 @@ import type { AgentConfig, CategoryConfig, GeneratedOmoConfig, ProviderAvailability } from "./model-fallback-types" const OPENAI_ONLY_AGENT_OVERRIDES: Record = { - explore: { model: "openai/gpt-5.4", variant: "medium" }, - librarian: { model: "openai/gpt-5.4", variant: "medium" }, + explore: { model: "openai/gpt-5.4-mini-fast" }, + librarian: { model: "openai/gpt-5.4-mini-fast" }, } const OPENAI_ONLY_CATEGORY_OVERRIDES: Record = { diff --git a/src/cli/provider-model-id-transform.test.ts b/src/cli/provider-model-id-transform.test.ts index d745ff097..0a1b57030 100644 --- a/src/cli/provider-model-id-transform.test.ts +++ b/src/cli/provider-model-id-transform.test.ts @@ -5,16 +5,16 @@ import { transformModelForProvider as transformSharedModelForProvider } from ".. describe("transformModelForProvider", () => { describe("github-copilot provider", () => { - test("transforms claude-opus-4-6 to claude-opus-4.6", () => { - // #given github-copilot provider and claude-opus-4-6 model + test("transforms claude-opus-4-7 to claude-opus-4.7", () => { + // #given github-copilot provider and claude-opus-4-7 model const provider = "github-copilot" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-opus-4.6 - expect(result).toBe("claude-opus-4.6") + // #then should transform to claude-opus-4.7 + expect(result).toBe("claude-opus-4.7") }) test("transforms claude-sonnet-4-5 to claude-sonnet-4.5", () => { @@ -152,32 +152,32 @@ describe("transformModelForProvider", () => { }) test("does not transform claude models for google provider", () => { - // #given google provider and claude-opus-4-6 model + // #given google provider and claude-opus-4-7 model const provider = "google" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) // #then should pass through unchanged (google doesn't use claude) - expect(result).toBe("claude-opus-4-6") + expect(result).toBe("claude-opus-4-7") }) }) describe("anthropic provider", () => { - test("transforms claude-opus-4-6 to claude-opus-4.6", () => { - // #given anthropic provider and claude-opus-4-6 model + test("preserves hyphenated claude-opus-4-7 for config output (regression: installer must not write dotted IDs)", () => { + // #given anthropic provider and claude-opus-4-7 model const provider = "anthropic" - const model = "claude-opus-4-6" + const model = "claude-opus-4-7" // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-opus-4.6 - expect(result).toBe("claude-opus-4.6") + // #then should keep hyphenated form so Anthropic provider resolution succeeds on fresh installs + expect(result).toBe("claude-opus-4-7") }) - test("transforms claude-sonnet-4-6 to claude-sonnet-4.6", () => { + test("preserves hyphenated claude-sonnet-4-6 for config output", () => { // #given anthropic provider and claude-sonnet-4-6 model const provider = "anthropic" const model = "claude-sonnet-4-6" @@ -185,11 +185,11 @@ describe("transformModelForProvider", () => { // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-sonnet-4.6 - expect(result).toBe("claude-sonnet-4.6") + // #then should keep hyphenated form + expect(result).toBe("claude-sonnet-4-6") }) - test("transforms claude-haiku-4-5 to claude-haiku-4.5", () => { + test("preserves hyphenated claude-haiku-4-5 for config output", () => { // #given anthropic provider and claude-haiku-4-5 model const provider = "anthropic" const model = "claude-haiku-4-5" @@ -197,19 +197,19 @@ describe("transformModelForProvider", () => { // #when transformModelForProvider is called const result = transformModelForProvider(provider, model) - // #then should transform to claude-haiku-4.5 - expect(result).toBe("claude-haiku-4.5") + // #then should keep hyphenated form + expect(result).toBe("claude-haiku-4-5") }) }) describe("vercel provider", () => { test("prepends anthropic/ and applies anthropic transform for claude models", () => { - // #given vercel provider and claude-opus-4-6 model + // #given vercel provider and claude-opus-4-7 model // #when transformModelForProvider is called - const result = transformModelForProvider("vercel", "claude-opus-4-6") + const result = transformModelForProvider("vercel", "claude-opus-4-7") - // #then should produce anthropic/claude-opus-4.6 - expect(result).toBe("anthropic/claude-opus-4.6") + // #then should produce anthropic/claude-opus-4.7 + expect(result).toBe("anthropic/claude-opus-4.7") }) test("prepends anthropic/ and applies anthropic transform for claude-sonnet", () => { @@ -267,12 +267,12 @@ describe("transformModelForProvider", () => { }) test("delegates to sub-provider when model already has sub-provider prefix", () => { - // #given vercel provider and anthropic/claude-opus-4-6 (already prefixed) + // #given vercel provider and anthropic/claude-opus-4-7 (already prefixed) // #when transformModelForProvider is called - const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-6") + const result = transformModelForProvider("vercel", "anthropic/claude-opus-4-7") // #then should apply anthropic transform within the prefix - expect(result).toBe("anthropic/claude-opus-4.6") + expect(result).toBe("anthropic/claude-opus-4.7") }) test("prepends minimax/ for minimax models", () => { @@ -338,14 +338,16 @@ describe("transformModelForProvider", () => { }) }) - test("uses a CLI-local transform implementation", () => { - // #given - const cliResult = transformModelForProvider("anthropic", "claude-opus-4-6") - const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-6") + test("uses a CLI-local transform implementation distinct from the shared runtime transform", () => { + // #given the CLI transform (used by the installer) and the shared runtime transform + const cliResult = transformModelForProvider("anthropic", "claude-opus-4-7") + const sharedResult = transformSharedModelForProvider("anthropic", "claude-opus-4-7") - // #when + // #when both are called with the same anthropic claude input + // #then the CLI preserves hyphenated form for config output, + // the shared runtime transform converts dash→dot for API calls expect(transformModelForProvider).not.toBe(transformSharedModelForProvider) - expect(cliResult).toBe("claude-opus-4.6") - expect(sharedResult).toBe("claude-opus-4.6") + expect(cliResult).toBe("claude-opus-4-7") + expect(sharedResult).toBe("claude-opus-4.7") }) }) diff --git a/src/cli/provider-model-id-transform.ts b/src/cli/provider-model-id-transform.ts index 82942fe74..fda947c8c 100644 --- a/src/cli/provider-model-id-transform.ts +++ b/src/cli/provider-model-id-transform.ts @@ -54,7 +54,12 @@ export function transformModelForProvider(provider: string, model: string): stri } if (provider === "anthropic") { - return claudeVersionDot(model) + // Installer writes hyphenated IDs (claude-opus-4-7) to the config. The + // runtime provider-model-id-transform converts dash→dot when calling the + // Anthropic API. Keeping the dotted form in the config breaks fresh + // installs with ProviderModelNotFoundError because Anthropic's provider + // registers models under hyphenated IDs. + return model } return model diff --git a/src/cli/refresh-model-capabilities.test.ts b/src/cli/refresh-model-capabilities.test.ts index 800cf7e54..bfed41969 100644 --- a/src/cli/refresh-model-capabilities.test.ts +++ b/src/cli/refresh-model-capabilities.test.ts @@ -49,7 +49,7 @@ describe("refreshModelCapabilities", () => { sourceUrl: "https://override.example/api.json", models: { "gpt-5.4": { id: "gpt-5.4" }, - "claude-opus-4-6": { id: "claude-opus-4-6" }, + "claude-opus-4-7": { id: "claude-opus-4-7" }, }, })) let stdout = "" diff --git a/src/cli/run/message-part-delta.test.ts b/src/cli/run/message-part-delta.test.ts index 6d7fefa6e..09f0c2d84 100644 --- a/src/cli/run/message-part-delta.test.ts +++ b/src/cli/run/message-part-delta.test.ts @@ -98,7 +98,7 @@ describe("message.part.delta handling", () => { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", }, }, @@ -113,7 +113,7 @@ describe("message.part.delta handling", () => { //#then const rendered = stdoutSpy.mock.calls.map((call) => String(call[0] ?? "")).join("") expect(rendered).toContain("\u001b[38;2;0;206;209m") - expect(rendered).toContain("claude-opus-4-6 (max)") + expect(rendered).toContain("claude-opus-4-7 (max)") expect(rendered).toContain("└─") expect(rendered).toContain("Sisyphus - Ultraworker") stdoutSpy.mockRestore() @@ -128,7 +128,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -187,7 +187,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -242,7 +242,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -309,7 +309,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -353,7 +353,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6", variant: "max" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7", variant: "max" }, }, }, { @@ -388,7 +388,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -410,7 +410,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-7" }, }, }, { @@ -619,7 +619,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, + info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" }, }, }, { @@ -634,7 +634,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-6" }, + info: { id: "msg_1", sessionID: "ses_main", role: "assistant", agent: "Sisyphus", modelID: "claude-opus-4-7" }, }, }, { diff --git a/src/cli/run/server-connection.test.ts b/src/cli/run/server-connection.test.ts index 90bad1812..2cd4ed660 100644 --- a/src/cli/run/server-connection.test.ts +++ b/src/cli/run/server-connection.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, mock, beforeEach, afterEach, afterAll } from "bun import * as originalSdk from "@opencode-ai/sdk" import * as originalPortUtils from "../../shared/port-utils" import * as originalBinaryResolver from "./opencode-binary-resolver" +import * as originalServerAuth from "../../shared/opencode-server-auth" const originalConsole = globalThis.console @@ -13,11 +14,15 @@ const mockCreateOpencode = mock(() => server: { url: "http://127.0.0.1:4096", close: mockServerClose }, }) ) -const mockCreateOpencodeClient = mock(() => ({ session: {} })) +const mockCreateOpencodeClient = mock((options?: { baseUrl?: string }) => ({ + session: {}, + baseUrl: options?.baseUrl, +})) const mockIsPortAvailable = mock(() => Promise.resolve(true)) const mockGetAvailableServerPort = mock(() => Promise.resolve({ port: 4096, wasAutoSelected: false })) const mockConsoleLog = mock(() => {}) const mockWithWorkingOpencodePath = mock((startServer: () => Promise) => startServer()) +const mockInjectServerAuthIntoClient = mock(() => {}) mock.module("@opencode-ai/sdk", () => ({ createOpencode: mockCreateOpencode, @@ -34,10 +39,15 @@ mock.module("./opencode-binary-resolver", () => ({ withWorkingOpencodePath: mockWithWorkingOpencodePath, })) +mock.module("../../shared/opencode-server-auth", () => ({ + injectServerAuthIntoClient: mockInjectServerAuthIntoClient, +})) + afterAll(() => { mock.module("@opencode-ai/sdk", () => originalSdk) mock.module("../../shared/port-utils", () => originalPortUtils) mock.module("./opencode-binary-resolver", () => originalBinaryResolver) + mock.module("../../shared/opencode-server-auth", () => originalServerAuth) mock.restore() }) @@ -52,6 +62,7 @@ describe("createServerConnection", () => { mockServerClose.mockClear() mockConsoleLog.mockClear() mockWithWorkingOpencodePath.mockClear() + mockInjectServerAuthIntoClient.mockClear() globalThis.console = { ...console, log: mockConsoleLog } as typeof console }) @@ -59,6 +70,49 @@ describe("createServerConnection", () => { globalThis.console = originalConsole }) + it("attach mode injects auth only for loopback URLs", async () => { + // given + const signal = new AbortController().signal + + // when + const localhostResult = await createServerConnection({ attach: "http://localhost:8080", signal }) + const loopbackResult = await createServerConnection({ attach: "http://127.0.0.1:8080", signal }) + const anyBindResult = await createServerConnection({ attach: "http://0.0.0.0:8080", signal }) + const remoteResult = await createServerConnection({ attach: "https://example.com", signal }) + + // then + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://localhost:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://127.0.0.1:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://0.0.0.0:8080" }) + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: "https://example.com" }) + expect(mockInjectServerAuthIntoClient).toHaveBeenCalledTimes(3) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(1, localhostResult.client) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(2, loopbackResult.client) + expect(mockInjectServerAuthIntoClient).toHaveBeenNthCalledWith(3, anyBindResult.client) + expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalledWith(remoteResult.client) + expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled() + localhostResult.cleanup() + loopbackResult.cleanup() + anyBindResult.cleanup() + remoteResult.cleanup() + expect(mockServerClose).not.toHaveBeenCalled() + }) + + it("attach mode skips auth injection for invalid attach URLs", async () => { + // given + const signal = new AbortController().signal + const attachUrl = "not-a-url" + + // when + const result = await createServerConnection({ attach: attachUrl, signal }) + + // then + expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl }) + expect(mockInjectServerAuthIntoClient).not.toHaveBeenCalled() + result.cleanup() + expect(mockServerClose).not.toHaveBeenCalled() + }) + it("attach mode returns client with no-op cleanup", async () => { // given const signal = new AbortController().signal @@ -68,8 +122,6 @@ describe("createServerConnection", () => { const result = await createServerConnection({ attach: attachUrl, signal }) // then - expect(mockCreateOpencodeClient).toHaveBeenCalledWith({ baseUrl: attachUrl }) - expect(mockWithWorkingOpencodePath).not.toHaveBeenCalled() expect(result.client).toBeDefined() expect(result.cleanup).toBeDefined() result.cleanup() diff --git a/src/cli/run/server-connection.ts b/src/cli/run/server-connection.ts index bf658ff05..f92aa1a08 100644 --- a/src/cli/run/server-connection.ts +++ b/src/cli/run/server-connection.ts @@ -1,9 +1,21 @@ import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk" import pc from "picocolors" import type { ServerConnection } from "./types" +import { injectServerAuthIntoClient } from "../../shared/opencode-server-auth" import { getAvailableServerPort, isPortAvailable, DEFAULT_SERVER_PORT } from "../../shared/port-utils" import { withWorkingOpencodePath } from "./opencode-binary-resolver" +const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"]) + +function isLoopbackAttachUrl(url: string): boolean { + try { + const parsed = new URL(url) + return LOOPBACK_HOSTS.has(parsed.hostname) + } catch { + return false + } +} + function isPortStartFailure(error: unknown, port: number): boolean { if (!(error instanceof Error)) { return false @@ -40,6 +52,9 @@ export async function createServerConnection(options: { if (attach !== undefined) { console.log(pc.dim("Attaching to existing server at"), pc.cyan(attach)) const client = createOpencodeClient({ baseUrl: attach }) + if (isLoopbackAttachUrl(attach)) { + injectServerAuthIntoClient(client) + } return { client, cleanup: () => {} } } @@ -66,12 +81,14 @@ export async function createServerConnection(options: { console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("became occupied, attaching to existing server")) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } } console.log(pc.dim("Port"), pc.cyan(port.toString()), pc.dim("is occupied, attaching to existing server")) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } @@ -93,6 +110,7 @@ export async function createServerConnection(options: { console.log(pc.dim("Port range exhausted, attaching to existing server on"), pc.cyan(DEFAULT_SERVER_PORT.toString())) const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` }) + injectServerAuthIntoClient(client) return { client, cleanup: () => {} } } diff --git a/src/cli/tui-install-prompts.ts b/src/cli/tui-install-prompts.ts index 3d5fb4584..9638dfd4d 100644 --- a/src/cli/tui-install-prompts.ts +++ b/src/cli/tui-install-prompts.ts @@ -74,7 +74,7 @@ export async function promptInstallConfig(detected: DetectedConfig): Promise { }) }) - describe("maxDescendants", () => { - describe("#given valid maxDescendants (50)", () => { - test("#when parsed #then returns correct value", () => { - const result = BackgroundTaskConfigSchema.parse({ maxDescendants: 50 }) - - expect(result.maxDescendants).toBe(50) - }) - }) - - describe("#given maxDescendants below minimum (0)", () => { - test("#when parsed #then throws ZodError", () => { - let thrownError: unknown - - try { - BackgroundTaskConfigSchema.parse({ maxDescendants: 0 }) - } catch (error) { - thrownError = error - } - - expect(thrownError).toBeInstanceOf(ZodError) - }) - }) - }) - describe("syncPollTimeoutMs", () => { describe("#given valid syncPollTimeoutMs (120000)", () => { test("#when parsed #then returns correct value", () => { diff --git a/src/config/schema/background-task.ts b/src/config/schema/background-task.ts index 44d16b505..4b62612fa 100644 --- a/src/config/schema/background-task.ts +++ b/src/config/schema/background-task.ts @@ -11,7 +11,6 @@ export const BackgroundTaskConfigSchema = z.object({ providerConcurrency: z.record(z.string(), z.number().min(0)).optional(), modelConcurrency: z.record(z.string(), z.number().min(0)).optional(), maxDepth: z.number().int().min(1).optional(), - maxDescendants: z.number().int().min(1).optional(), /** Stale timeout in milliseconds - interrupt tasks with no activity for this duration (default: 180000 = 3 minutes, minimum: 60000 = 1 minute) */ staleTimeoutMs: z.number().min(60000).optional(), /** Timeout for tasks that never received any progress update, falling back to startedAt (default: 1800000 = 30 minutes, minimum: 60000 = 1 minute) */ diff --git a/src/create-hooks.ts b/src/create-hooks.ts index 0e40ad480..436f8e2b9 100644 --- a/src/create-hooks.ts +++ b/src/create-hooks.ts @@ -2,6 +2,7 @@ import type { AvailableSkill } from "./agents/dynamic-agent-prompt-builder" import type { HookName, OhMyOpenCodeConfig } from "./config" import type { LoadedSkill } from "./features/opencode-skill-loader/types" import type { BackgroundManager } from "./features/background-agent" +import type { ModelFallbackControllerAccessor } from "./hooks/model-fallback" import type { PluginContext } from "./plugin/types" import type { ModelCacheState } from "./plugin-state" @@ -36,6 +37,7 @@ export function createHooks(args: { pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState backgroundManager: BackgroundManager + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean mergedSkills: LoadedSkill[] @@ -46,6 +48,7 @@ export function createHooks(args: { pluginConfig, modelCacheState, backgroundManager, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, mergedSkills, @@ -56,6 +59,7 @@ export function createHooks(args: { ctx, pluginConfig, modelCacheState, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, }) diff --git a/src/create-managers.ts b/src/create-managers.ts index d40896343..9c0013fd4 100644 --- a/src/create-managers.ts +++ b/src/create-managers.ts @@ -5,6 +5,7 @@ import type { PluginContext, TmuxConfig } from "./plugin/types" import type { SubagentSessionCreatedEvent } from "./features/background-agent" import { BackgroundManager } from "./features/background-agent" import { SkillMcpManager } from "./features/skill-mcp-manager" +import { createModelFallbackControllerAccessor } from "./hooks/model-fallback" import { initTaskToastManager } from "./features/task-toast-manager" import { TmuxSessionManager } from "./features/tmux-subagent" import * as openclawRuntimeDispatch from "./openclaw/runtime-dispatch" @@ -12,6 +13,7 @@ import { registerManagerForCleanup } from "./features/background-agent/process-c import { createConfigHandler } from "./plugin-handlers" import { log } from "./shared" import { markServerRunningInProcess } from "./shared/tmux/tmux-utils/server-health" +import type { ModelFallbackControllerAccessor } from "./hooks/model-fallback" type CreateManagersDeps = { BackgroundManagerClass: typeof BackgroundManager @@ -38,6 +40,7 @@ export type Managers = { backgroundManager: BackgroundManager skillMcpManager: SkillMcpManager configHandler: ReturnType + modelFallbackControllerAccessor: ModelFallbackControllerAccessor } export function createManagers(args: { @@ -119,11 +122,13 @@ export function createManagers(args: { pluginConfig, modelCacheState, }) + const modelFallbackControllerAccessor = createModelFallbackControllerAccessor() return { tmuxSessionManager, backgroundManager, skillMcpManager, configHandler, + modelFallbackControllerAccessor, } } diff --git a/src/create-tools.ts b/src/create-tools.ts index 5ac5a7e2f..6a9bc3941 100644 --- a/src/create-tools.ts +++ b/src/create-tools.ts @@ -22,7 +22,7 @@ type CreateToolsResult = { export async function createTools(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig - managers: Pick + managers: Pick }): Promise { const { ctx, pluginConfig, managers } = args diff --git a/src/features/AGENTS.md b/src/features/AGENTS.md index ff920a1bd..5deea8450 100644 --- a/src/features/AGENTS.md +++ b/src/features/AGENTS.md @@ -1,6 +1,6 @@ # src/features/ — 19 Feature Modules -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/features/background-agent/AGENTS.md b/src/features/background-agent/AGENTS.md index bac2302fe..6c6761eee 100644 --- a/src/features/background-agent/AGENTS.md +++ b/src/features/background-agent/AGENTS.md @@ -44,7 +44,7 @@ Both must agree before marking a task complete. Prevents premature completion on ## CONCURRENCY MODEL -- Key format: `{providerID}/{modelID}` (e.g., `anthropic/claude-opus-4-6`) +- Key format: `{providerID}/{modelID}` (e.g., `anthropic/claude-opus-4-7`) - Default limit: 5 concurrent per key (configurable via `background_task` config) - FIFO queue: tasks wait in order when slots full - Slot released on: completion, error, cancellation diff --git a/src/features/background-agent/compaction-aware-message-resolver.test.ts b/src/features/background-agent/compaction-aware-message-resolver.test.ts index 07fc8b448..4ad9a33cf 100644 --- a/src/features/background-agent/compaction-aware-message-resolver.test.ts +++ b/src/features/background-agent/compaction-aware-message-resolver.test.ts @@ -83,7 +83,7 @@ describe("findNearestMessageExcludingCompaction", () => { // given const message = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(tempDir, "001.json"), JSON.stringify(message)) @@ -94,18 +94,18 @@ describe("findNearestMessageExcludingCompaction", () => { expect(result).not.toBeNull() expect(result?.agent).toBe("sisyphus") expect(result?.model?.providerID).toBe("anthropic") - expect(result?.model?.modelID).toBe("claude-opus-4-6") + expect(result?.model?.modelID).toBe("claude-opus-4-7") }) test("skips compaction agent messages", () => { // given const compactionMessage = { agent: "compaction", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } const validMessage = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(tempDir, "002.json"), JSON.stringify(compactionMessage)) writeFileSync(join(tempDir, "001.json"), JSON.stringify(validMessage)) @@ -125,12 +125,12 @@ describe("findNearestMessageExcludingCompaction", () => { writeFileSync(join(tempDir, "002.json"), JSON.stringify({ id: compactionMessageID, agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, })) writeFileSync(join(tempDir, "001.json"), JSON.stringify({ id: "msg_001", agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, })) mkdirSync(partDir, { recursive: true }) writeFileSync(join(partDir, "prt_0001.json"), JSON.stringify({ type: "compaction" })) diff --git a/src/features/background-agent/concurrency.test.ts b/src/features/background-agent/concurrency.test.ts index 682d6029a..45150f79b 100644 --- a/src/features/background-agent/concurrency.test.ts +++ b/src/features/background-agent/concurrency.test.ts @@ -94,7 +94,7 @@ describe("ConcurrencyManager.getConcurrencyLimit", () => { // when const modelLimit = manager.getConcurrencyLimit("anthropic/claude-sonnet-4-6") - const providerLimit = manager.getConcurrencyLimit("anthropic/claude-opus-4-6") + const providerLimit = manager.getConcurrencyLimit("anthropic/claude-opus-4-7") const defaultLimit = manager.getConcurrencyLimit("google/gemini-3.1-pro") // then diff --git a/src/features/background-agent/index.ts b/src/features/background-agent/index.ts index e1d1a9b73..d21b2faa8 100644 --- a/src/features/background-agent/index.ts +++ b/src/features/background-agent/index.ts @@ -1,2 +1,4 @@ export * from "./types" export { BackgroundManager, type SubagentSessionCreatedEvent, type OnSubagentSessionCreated } from "./manager" +export { waitForTaskSessionID } from "./wait-for-task-session" +export type { WaitForTaskSessionIDOptions } from "./wait-for-task-session" diff --git a/src/features/background-agent/manager.test.ts b/src/features/background-agent/manager.test.ts index 7ad6fea39..8c855ebcf 100644 --- a/src/features/background-agent/manager.test.ts +++ b/src/features/background-agent/manager.test.ts @@ -855,7 +855,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => { info: { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, }, }, { @@ -890,7 +890,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => //#then expect(capturedBody?.agent).toBe("sisyphus") - expect(capturedBody?.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(capturedBody?.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) manager.shutdown() }) @@ -913,7 +913,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => } const currentMessage: CurrentMessage = { agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } // when @@ -921,7 +921,7 @@ describe("BackgroundManager.notifyParentSession - dynamic message lookup", () => // then - uses currentMessage values, not task.parentModel/parentAgent expect(promptBody.agent).toBe("sisyphus") - expect(promptBody.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(promptBody.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) }) test("should fallback to parentAgent when currentMessage.agent is undefined", async () => { @@ -1155,7 +1155,7 @@ describe("BackgroundManager.notifyParentSession - notifications toggle", () => { agent: "explore", model: { providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "high", }, }, @@ -1211,7 +1211,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { agent: "explore", model: { providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }, }, @@ -1231,7 +1231,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { status: "completed", startedAt: new Date(), completedAt: new Date(), - model: { providerID: "anthropic", modelID: "claude-opus-4.6", variant: "high" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7", variant: "high" }, } getPendingByParent(manager).set("session-parent", new Set([task.id])) @@ -1272,7 +1272,7 @@ describe("BackgroundManager.notifyParentSession - variant propagation", () => { status: "completed", startedAt: new Date(), completedAt: new Date(), - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getPendingByParent(manager).set("session-parent", new Set([task.id])) @@ -1349,7 +1349,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release concurrency and clear key on completion", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) await concurrencyManager.acquire(concurrencyKey) @@ -1378,7 +1378,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should prevent double completion and double release", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) await concurrencyManager.acquire(concurrencyKey) @@ -1508,7 +1508,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release task concurrencyKey when startTask throws after assigning it", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) const task = createMockTask({ @@ -1524,7 +1524,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -1544,7 +1544,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should mark task as error when startTask throws after session creation", async () => { //#given - startTask creates session but fails before sending prompt - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const task = createMockTask({ id: "task-zombie-session", @@ -1561,7 +1561,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -1585,7 +1585,7 @@ describe("BackgroundManager.tryCompleteTask", () => { test("should release queue slot when queued task is already interrupt", async () => { // given - const concurrencyKey = "anthropic/claude-opus-4.6" + const concurrencyKey = "anthropic/claude-opus-4.7" const concurrencyManager = getConcurrencyManager(manager) const task = createMockTask({ @@ -1601,7 +1601,7 @@ describe("BackgroundManager.tryCompleteTask", () => { agent: task.agent, parentSessionID: task.parentSessionID, parentMessageID: task.parentMessageID, - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } getTaskMap(manager).set(task.id, task) getQueuesByKey(manager).set(concurrencyKey, [{ task, input }]) @@ -2104,7 +2104,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { agent: "test-agent", parentSessionID: "parent-session", parentMessageID: "parent-message", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, } const launchInputWithoutModel = { description: "Test task without model", @@ -2124,7 +2124,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { expect(taskWithModel.status).toBe("pending") expect(taskWithoutModel.status).toBe("pending") expect(promptBodies).toHaveLength(2) - expect(promptBodies[0].model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.6" }) + expect(promptBodies[0].model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4.7" }) expect(promptBodies[0].agent).toBe("test-agent") expect(promptBodies[1].agent).toBe("test-agent") expect("model" in promptBodies[1]).toBe(false) @@ -2327,7 +2327,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(result).rejects.toThrow("background_task.maxDepth=3") }) - test("should block launches when maxDescendants is reached", async () => { + test("allows multiple descendants without a root spawn cap", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2337,7 +2337,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2354,10 +2353,10 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.launch(input) // then - await expect(result).rejects.toThrow("background_task.maxDescendants=1") + await expect(result).resolves.toBeDefined() }) - test("should consume descendant quota for reserved sync spawns", async () => { + test("allows spawn assertions after reserveSubagentSpawn without a root spawn cap", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2367,7 +2366,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) await manager.reserveSubagentSpawn("session-root") @@ -2376,7 +2374,10 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.assertCanSpawn("session-root") // then - await expect(result).rejects.toThrow("background_task.maxDescendants=1") + await expect(result).resolves.toMatchObject({ + rootSessionID: "session-root", + childDepth: 1, + }) }) test("should fail closed when session lineage lookup fails", async () => { @@ -2392,7 +2393,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { ), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2407,10 +2407,10 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { const result = manager.launch(input) // then - await expect(result).rejects.toThrow("background_task.maxDescendants cannot be enforced safely") + await expect(result).rejects.toThrow("background_task.maxDepth cannot be enforced safely") }) - test("should release descendant quota when queued task is cancelled before session starts", async () => { + test("allows replacement launch when a queued task is cancelled before session starts", async () => { // given manager.shutdown() manager = new BackgroundManager( @@ -2420,7 +2420,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { defaultConcurrency: 1, maxDescendants: 2 }, + { defaultConcurrency: 1 }, ) const input = { @@ -2445,7 +2445,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { expect(replacementTask.status).toBe("pending") }) - test("should release descendant quota when session creation fails before session starts", async () => { + test("allows retry after session creation fails before session starts", async () => { // given let createAttempts = 0 manager.shutdown() @@ -2472,7 +2472,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }, directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2887,7 +2886,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { } }) - test("should release descendant quota when task completes", async () => { + test("allows relaunch after task completes", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2896,7 +2895,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) stubNotifyParentSession(manager) @@ -2920,7 +2918,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should release descendant quota when running task is cancelled", async () => { + test("allows relaunch after running task is cancelled", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2929,7 +2927,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2950,7 +2947,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should release descendant quota when task errors", async () => { + test("allows relaunch after task errors", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2959,7 +2956,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 1 }, ) const input = { @@ -2984,7 +2980,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { await expect(manager.launch(input)).resolves.toBeDefined() }) - test("should not double-decrement quota when pending task is cancelled", async () => { + test("allows repeated relaunch after pending tasks are cancelled", async () => { manager.shutdown() manager = new BackgroundManager( { @@ -2993,7 +2989,6 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { }), directory: tmpdir(), } as unknown as PluginInput, - { maxDescendants: 2 }, ) const input = { @@ -3250,7 +3245,7 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => { description: "Task 1", prompt: "Do something", agent: "test-agent", - model: { providerID: "anthropic", modelID: "claude-opus-4.6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7" }, parentSessionID: "parent-session", parentMessageID: "parent-message", } @@ -4230,7 +4225,7 @@ describe("BackgroundManager.handleEvent - session.deleted cascade", () => { describe("BackgroundManager.handleEvent - session.error", () => { const defaultRetryFallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["anthropic"], model: "gpt-5.3-codex", variant: "high" }, ] @@ -4254,7 +4249,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { agent: "sisyphus", status: "running", concurrencyKey: input.concurrencyKey, - model: { providerID: "anthropic", modelID: "claude-opus-4.6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4.7-thinking" }, fallbackChain: input.fallbackChain ?? defaultRetryFallbackChain, attemptCount: 0, }) @@ -4399,7 +4394,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { //#given const manager = createBackgroundManager() const concurrencyManager = getConcurrencyManager(manager) - const concurrencyKey = "anthropic/claude-opus-4.6-thinking" + const concurrencyKey = "anthropic/claude-opus-4.7-thinking" await concurrencyManager.acquire(concurrencyKey) stubProcessKey(manager) @@ -4411,7 +4406,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { description: "task that should retry", concurrencyKey, fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["anthropic"], model: "claude-opus-4-5", variant: "max" }, ], }) @@ -4425,7 +4420,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { name: "UnknownError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.7-thinking\"}}", }, }, }, @@ -4436,7 +4431,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) expect(task.concurrencyKey).toBeUndefined() @@ -4474,7 +4469,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) @@ -4502,7 +4497,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { name: "UnknownError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4.7-thinking\"}}", }, }, } @@ -4519,7 +4514,7 @@ describe("BackgroundManager.handleEvent - session.error", () => { expect(task.attemptCount).toBe(1) expect(task.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4.6", + modelID: "claude-opus-4.7", variant: "max", }) diff --git a/src/features/background-agent/manager.ts b/src/features/background-agent/manager.ts index e50e8f468..481fbbae0 100644 --- a/src/features/background-agent/manager.ts +++ b/src/features/background-agent/manager.ts @@ -73,8 +73,6 @@ import { } from "./loop-detector" import { createSubagentDepthLimitError, - createSubagentDescendantLimitError, - getMaxRootSessionSpawnBudget, getMaxSubagentDepth, resolveSubagentSpawnContext, type SubagentSpawnContext, @@ -219,16 +217,6 @@ export class BackgroundManager { }) } - const maxRootSessionSpawnBudget = getMaxRootSessionSpawnBudget(this.config) - const descendantCount = this.rootDescendantCounts.get(spawnContext.rootSessionID) ?? 0 - if (descendantCount >= maxRootSessionSpawnBudget) { - throw createSubagentDescendantLimitError({ - rootSessionID: spawnContext.rootSessionID, - descendantCount, - maxDescendants: maxRootSessionSpawnBudget, - }) - } - return spawnContext } diff --git a/src/features/background-agent/process-cleanup.test-helpers.ts b/src/features/background-agent/process-cleanup.test-helpers.ts new file mode 100644 index 000000000..c0a3dfa2d --- /dev/null +++ b/src/features/background-agent/process-cleanup.test-helpers.ts @@ -0,0 +1,27 @@ +type ProcessCleanupEvent = + | NodeJS.Signals + | "beforeExit" + | "exit" + | "uncaughtException" + | "unhandledRejection" + +export function getNewListener( + signal: ProcessCleanupEvent, + existingListeners: Function[], +): () => void { + const listener = process + .listeners(signal) + .find((registeredListener) => !existingListeners.includes(registeredListener)) + + if (typeof listener !== "function") { + throw new Error(`Expected a ${signal} listener to be registered`) + } + + return listener +} + +export async function flushMicrotasks(): Promise { + for (let iteration = 0; iteration < 10; iteration += 1) { + await Promise.resolve() + } +} diff --git a/src/features/background-agent/process-cleanup.test.ts b/src/features/background-agent/process-cleanup.test.ts index 7d01aaa21..a9ce35435 100644 --- a/src/features/background-agent/process-cleanup.test.ts +++ b/src/features/background-agent/process-cleanup.test.ts @@ -1,3 +1,5 @@ +/// + import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test" import { @@ -5,42 +7,17 @@ import { registerManagerForCleanup, unregisterManagerForCleanup, } from "./process-cleanup" +import { flushMicrotasks, getNewListener } from "./process-cleanup.test-helpers" type CleanupManager = { shutdown: () => void | Promise } -type ProcessCleanupEvent = NodeJS.Signals | "beforeExit" | "exit" - -function getNewListener( - signal: ProcessCleanupEvent, - existingListeners: Function[], -): () => void { - const listener = process - .listeners(signal) - .find((registeredListener) => !existingListeners.includes(registeredListener)) - - expect(listener).toBeDefined() - - if (typeof listener !== "function") { - throw new Error(`Expected a ${signal} listener to be registered`) - } - - return listener -} - -async function flushMicrotasks(): Promise { - for (let iteration = 0; iteration < 10; iteration += 1) { - await Promise.resolve() - } -} - describe("#given process cleanup registration", () => { const registeredManagers: CleanupManager[] = [] - const originalExitCode = process.exitCode beforeEach(() => { - process.exitCode = originalExitCode + process.exitCode = 0 registeredManagers.length = 0 _resetForTesting() }) @@ -50,7 +27,7 @@ describe("#given process cleanup registration", () => { unregisterManagerForCleanup(manager) } - process.exitCode = originalExitCode + process.exitCode = 0 _resetForTesting() }) @@ -92,13 +69,7 @@ describe("#given process cleanup registration", () => { test("#when cleanup finishes after SIGINT #then the fallback exit timer is cleared", async () => { const sigintListenersBefore = process.listeners("SIGINT") - const timeoutHandle = setTimeout(() => undefined, 0) - clearTimeout(timeoutHandle) - - const setTimeoutImplementation: typeof setTimeout = () => timeoutHandle - const setTimeoutSpy = spyOn(globalThis, "setTimeout").mockImplementation( - setTimeoutImplementation, - ) + const setTimeoutSpy = spyOn(globalThis, "setTimeout") const clearTimeoutSpy = spyOn(globalThis, "clearTimeout") try { @@ -117,11 +88,10 @@ describe("#given process cleanup registration", () => { await flushMicrotasks() expect(setTimeoutSpy).toHaveBeenCalledTimes(1) - expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutHandle) + expect(clearTimeoutSpy).toHaveBeenCalledTimes(1) } finally { setTimeoutSpy.mockRestore() clearTimeoutSpy.mockRestore() - clearTimeout(timeoutHandle) } }) }) @@ -163,6 +133,32 @@ describe("#given process cleanup registration", () => { expect(process.listeners("SIGINT")).toHaveLength(sigintListenersAfterFirstRegistration) }) + + test("#given two managers registered #when uncaughtException fires #then both shutdowns called", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdownOne = mock(() => {}) + const shutdownTwo = mock(() => {}) + const managerOne = { shutdown: shutdownOne } + const managerTwo = { shutdown: shutdownTwo } + registeredManagers.push(managerOne, managerTwo) + + try { + registerManagerForCleanup(managerOne) + registerManagerForCleanup(managerTwo) + + process.emit("uncaughtException", new Error("boom")) + await flushMicrotasks() + + expect(shutdownOne).toHaveBeenCalledTimes(1) + expect(shutdownTwo).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) }) describe("#given cleanup managers are unregistered", () => { @@ -202,5 +198,88 @@ describe("#given process cleanup registration", () => { expect(remainingManagerShutdown).toHaveBeenCalledTimes(1) expect(removedManagerShutdown).not.toHaveBeenCalled() }) + + test("#given uncaughtException handler registered #when manager is unregistered via unregisterManagerForCleanup #then subsequent events do not invoke that manager", () => { + const uncaughtExceptionListenersBefore = process.listeners("uncaughtException") + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + registerManagerForCleanup(manager) + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length + 1, + ) + + unregisterManagerForCleanup(manager) + registeredManagers.length = 0 + process.emit("uncaughtException", new Error("boom")) + + expect(shutdown).not.toHaveBeenCalled() + }) + }) + + describe("#given uncaught exception and rejection cleanup", () => { + test("#given manager registered AND process emits uncaughtException #when event fires #then manager.shutdown() called AND process.exitCode set to 1", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + try { + registerManagerForCleanup(manager) + + process.emit("uncaughtException", new Error("boom")) + await flushMicrotasks() + + expect(shutdown).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) + + test("#given manager registered AND process emits unhandledRejection #when event fires #then manager.shutdown() called AND process.exitCode set to 1", async () => { + const exitSpy = spyOn(process, "exit").mockImplementation((code?: number): never => { + throw new Error(`Unexpected process.exit(${String(code)})`) + }) + const shutdown = mock(() => {}) + const manager = { shutdown } + registeredManagers.push(manager) + + try { + registerManagerForCleanup(manager) + + process.emit("unhandledRejection", new Error("boom"), Promise.resolve()) + await flushMicrotasks() + + expect(shutdown).toHaveBeenCalledTimes(1) + expect(process.exitCode).toBe(1) + expect(exitSpy).not.toHaveBeenCalled() + } finally { + exitSpy.mockRestore() + } + }) + + test("#given _resetForTesting() called #when event fires #then no cleanup runs", () => { + const uncaughtExceptionListenersBefore = process.listeners("uncaughtException") + const shutdown = mock(() => {}) + const manager = { shutdown } + + registerManagerForCleanup(manager) + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length + 1, + ) + + _resetForTesting() + process.emit("uncaughtException", new Error("boom")) + + expect(shutdown).not.toHaveBeenCalled() + expect(process.listeners("uncaughtException")).toHaveLength( + uncaughtExceptionListenersBefore.length, + ) + }) }) }) diff --git a/src/features/background-agent/process-cleanup.ts b/src/features/background-agent/process-cleanup.ts index 29be1958e..20f8fab00 100644 --- a/src/features/background-agent/process-cleanup.ts +++ b/src/features/background-agent/process-cleanup.ts @@ -1,33 +1,51 @@ import { log } from "../../shared" -type ProcessCleanupEvent = NodeJS.Signals | "beforeExit" | "exit" +type ProcessCleanupSignal = NodeJS.Signals | "beforeExit" | "exit" +type ProcessCleanupErrorEvent = "uncaughtException" | "unhandledRejection" + +function scheduleForcedExit(cleanupResult: void | Promise, exitCode: number): void { + process.exitCode = exitCode + const exitTimeout = setTimeout(() => process.exit(), 6000) + void Promise.resolve(cleanupResult).finally(() => { + clearTimeout(exitTimeout) + }) +} function registerProcessSignal( - signal: ProcessCleanupEvent, + signal: ProcessCleanupSignal, handler: () => void | Promise, exitAfter: boolean ): () => void { const listener = () => { const cleanupResult = handler() if (exitAfter) { - process.exitCode = 0 - const exitTimeout = setTimeout(() => process.exit(), 6000) - void Promise.resolve(cleanupResult).finally(() => { - clearTimeout(exitTimeout) - }) + scheduleForcedExit(cleanupResult, 0) } } process.on(signal, listener) return listener } +function registerErrorEvent( + signal: ProcessCleanupErrorEvent, + handler: (error: unknown) => void | Promise +): (error: unknown) => void { + const listener = (error: unknown) => { + log(`[background-agent] ${signal} received during shutdown cleanup:`, error) + scheduleForcedExit(handler(error), 1) + } + process.on(signal, listener) + return listener +} + interface CleanupTarget { shutdown(): void | Promise } const cleanupManagers = new Set() let cleanupRegistered = false -const cleanupHandlers = new Map void>() +const cleanupSignalHandlers = new Map void>() +const cleanupErrorHandlers = new Map void>() export function registerManagerForCleanup(manager: CleanupTarget): void { cleanupManagers.add(manager) @@ -59,9 +77,9 @@ export function registerManagerForCleanup(manager: CleanupTarget): void { return cleanupPromise } - const registerSignal = (signal: ProcessCleanupEvent, exitAfter: boolean): void => { + const registerSignal = (signal: ProcessCleanupSignal, exitAfter: boolean): void => { const listener = registerProcessSignal(signal, cleanupAll, exitAfter) - cleanupHandlers.set(signal, listener) + cleanupSignalHandlers.set(signal, listener) } registerSignal("SIGINT", true) @@ -71,6 +89,8 @@ export function registerManagerForCleanup(manager: CleanupTarget): void { } registerSignal("beforeExit", false) registerSignal("exit", false) + cleanupErrorHandlers.set("uncaughtException", registerErrorEvent("uncaughtException", cleanupAll)) + cleanupErrorHandlers.set("unhandledRejection", registerErrorEvent("unhandledRejection", cleanupAll)) } export function unregisterManagerForCleanup(manager: CleanupTarget): void { @@ -78,10 +98,14 @@ export function unregisterManagerForCleanup(manager: CleanupTarget): void { if (cleanupManagers.size > 0) return - for (const [signal, listener] of cleanupHandlers.entries()) { + for (const [signal, listener] of cleanupSignalHandlers.entries()) { process.off(signal, listener) } - cleanupHandlers.clear() + for (const [signal, listener] of cleanupErrorHandlers.entries()) { + process.off(signal, listener) + } + cleanupSignalHandlers.clear() + cleanupErrorHandlers.clear() cleanupRegistered = false } @@ -90,9 +114,13 @@ export function _resetForTesting(): void { for (const manager of [...cleanupManagers]) { cleanupManagers.delete(manager) } - for (const [signal, listener] of cleanupHandlers.entries()) { + for (const [signal, listener] of cleanupSignalHandlers.entries()) { process.off(signal, listener) } - cleanupHandlers.clear() + for (const [signal, listener] of cleanupErrorHandlers.entries()) { + process.off(signal, listener) + } + cleanupSignalHandlers.clear() + cleanupErrorHandlers.clear() cleanupRegistered = false } diff --git a/src/features/background-agent/spawner.test.ts b/src/features/background-agent/spawner.test.ts index b1f486c52..eb2cc294b 100644 --- a/src/features/background-agent/spawner.test.ts +++ b/src/features/background-agent/spawner.test.ts @@ -577,3 +577,84 @@ describe("background-agent spawner fallback model promotion", () => { expect(promptCalls[0]?.body?.agent).toBe("sisyphus-junior") }) }) + +describe("background-agent spawner tmux callback ordering", () => { + test("fires promptAsync before tmux callback resolves (no blocking)", async () => { + //#given + const events: string[] = [] + let resolveTmuxCallback: () => void = () => {} + const tmuxCallbackPromise = new Promise((resolve) => { + resolveTmuxCallback = resolve + }) + + const client = { + session: { + get: async () => ({ data: { directory: "/tmp/test" } }), + create: async () => { + events.push("session.create") + return { data: { id: "ses_blocking_tmux" } } + }, + promptAsync: async () => { + events.push("promptAsync") + return { data: {} } + }, + }, + } as any + + const onSubagentSessionCreated = mock(async () => { + events.push("tmux.callback.start") + await tmuxCallbackPromise + events.push("tmux.callback.end") + }) + + const task = createTask({ + description: "Blocking tmux test", + prompt: "Do work", + agent: "general", + parentSessionID: "ses_parent", + parentMessageID: "msg_parent", + }) + + const item = { + task, + input: { + description: task.description, + prompt: task.prompt, + agent: task.agent, + parentSessionID: task.parentSessionID, + parentMessageID: task.parentMessageID, + }, + } + + const ctx = { + client, + directory: "/tmp/test", + concurrencyManager: { release: () => {} }, + tmuxEnabled: true, + onSubagentSessionCreated, + onTaskError: () => {}, + } + + const originalTmux = process.env.TMUX + process.env.TMUX = "/tmp/fake-tmux-socket" + + try { + //#when + await startTask(item as any, ctx as any) + await new Promise((resolve) => setTimeout(resolve, 20)) + + //#then + expect(events).toContain("session.create") + expect(events).toContain("promptAsync") + expect(events).toContain("tmux.callback.start") + const promptIdx = events.indexOf("promptAsync") + const tmuxStartIdx = events.indexOf("tmux.callback.start") + expect(promptIdx < tmuxStartIdx).toBe(true) + expect(events).not.toContain("tmux.callback.end") + } finally { + resolveTmuxCallback() + if (originalTmux === undefined) delete process.env.TMUX + else process.env.TMUX = originalTmux + } + }) +}) diff --git a/src/features/background-agent/spawner.ts b/src/features/background-agent/spawner.ts index 675aeb5d9..ab6aaa2f1 100644 --- a/src/features/background-agent/spawner.ts +++ b/src/features/background-agent/spawner.ts @@ -1,6 +1,5 @@ import type { BackgroundTask, LaunchInput, ResumeInput } from "./types" import type { OpencodeClient, OnSubagentSessionCreated, QueueItem } from "./constants" -import { TMUX_CALLBACK_DELAY_MS } from "./constants" import { log, getAgentToolRestrictions, promptWithModelSuggestionRetry, createInternalAgentTextPart } from "../../shared" import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers" import { subagentSessions } from "../claude-code-session-state" @@ -115,29 +114,6 @@ export async function startTask( const sessionID = createResult.data.id subagentSessions.add(sessionID) - log("[background-agent] tmux callback check", { - hasCallback: !!onSubagentSessionCreated, - tmuxEnabled, - isInsideTmux: isInsideTmux(), - sessionID, - parentID: input.parentSessionID, - }) - - if (onSubagentSessionCreated && tmuxEnabled && isInsideTmux()) { - log("[background-agent] Invoking tmux callback NOW", { sessionID }) - await onSubagentSessionCreated({ - sessionID, - parentID: input.parentSessionID, - title: input.description, - }).catch((err) => { - log("[background-agent] Failed to spawn tmux pane:", err) - }) - log("[background-agent] tmux callback completed, waiting") - await new Promise(r => setTimeout(r, TMUX_CALLBACK_DELAY_MS)) - } else { - log("[background-agent] SKIP tmux callback - conditions not met") - } - task.status = "running" task.startedAt = new Date() task.sessionID = sessionID @@ -188,7 +164,8 @@ export async function startTask( parts: [createInternalAgentTextPart(input.prompt)], } - promptWithModelSuggestionRetry(client, { + // Must fire BEFORE tmux callback: attach client needs session activity to render TUI. + const promptChain = promptWithModelSuggestionRetry(client, { path: { id: sessionID }, body: promptBody, }).catch(async (error) => { @@ -214,6 +191,29 @@ export async function startTask( log("[background-agent] promptAsync error:", error) onTaskError(task, error instanceof Error ? error : new Error(String(error))) }) + + void promptChain + + log("[background-agent] tmux callback check", { + hasCallback: !!onSubagentSessionCreated, + tmuxEnabled, + isInsideTmux: isInsideTmux(), + sessionID, + parentID: input.parentSessionID, + }) + + if (onSubagentSessionCreated && tmuxEnabled && isInsideTmux()) { + log("[background-agent] Invoking tmux callback (fire-and-forget)", { sessionID }) + void onSubagentSessionCreated({ + sessionID, + parentID: input.parentSessionID, + title: input.description, + }).catch((err) => { + log("[background-agent] Failed to spawn tmux pane:", err) + }) + } else { + log("[background-agent] SKIP tmux callback - conditions not met") + } } export async function resumeTask( diff --git a/src/features/background-agent/subagent-spawn-limits.test.ts b/src/features/background-agent/subagent-spawn-limits.test.ts index e158c0dad..e3094c551 100644 --- a/src/features/background-agent/subagent-spawn-limits.test.ts +++ b/src/features/background-agent/subagent-spawn-limits.test.ts @@ -5,9 +5,6 @@ import { getMaxSubagentDepth, DEFAULT_MAX_SUBAGENT_DEPTH, createSubagentDepthLimitError, - createSubagentDescendantLimitError, - getMaxRootSessionSpawnBudget, - DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET, } from "./subagent-spawn-limits" function createMockClient(sessionGet: OpencodeClient["session"]["get"]): OpencodeClient { @@ -62,7 +59,7 @@ describe("resolveSubagentSpawnContext", () => { const result = resolveSubagentSpawnContext(client, "parent-session") // then - await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*lookup failed/) + await expect(result).rejects.toThrow(/background_task\.maxDepth cannot be enforced safely.*lookup failed/) }) }) @@ -77,7 +74,7 @@ describe("resolveSubagentSpawnContext", () => { const result = resolveSubagentSpawnContext(client, "parent-session") // then - await expect(result).rejects.toThrow(/background_task\.maxDescendants cannot be enforced safely.*No session data returned/) + await expect(result).rejects.toThrow(/background_task\.maxDepth cannot be enforced safely.*No session data returned/) }) }) @@ -209,20 +206,6 @@ describe("getMaxSubagentDepth", () => { }) }) -describe("getMaxRootSessionSpawnBudget", () => { - test("returns DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET when no config", () => { - expect(getMaxRootSessionSpawnBudget()).toBe(DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET) - }) - - test("returns config.maxDescendants when provided", () => { - expect(getMaxRootSessionSpawnBudget({ maxDescendants: 10 })).toBe(10) - }) - - test("default is 50", () => { - expect(DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET).toBe(50) - }) -}) - describe("createSubagentDepthLimitError", () => { test("includes childDepth, maxDepth, and session IDs in message", () => { const error = createSubagentDepthLimitError({ @@ -239,18 +222,3 @@ describe("createSubagentDepthLimitError", () => { expect(error.message).toContain("spawn blocked") }) }) - -describe("createSubagentDescendantLimitError", () => { - test("includes descendant count, max, and root session ID", () => { - const error = createSubagentDescendantLimitError({ - rootSessionID: "root-789", - descendantCount: 50, - maxDescendants: 50, - }) - - expect(error.message).toContain("root-789") - expect(error.message).toContain("50") - expect(error.message).toContain("maxDescendants=50") - expect(error.message).toContain("spawn blocked") - }) -}) diff --git a/src/features/background-agent/subagent-spawn-limits.ts b/src/features/background-agent/subagent-spawn-limits.ts index c53a0e358..9483f3247 100644 --- a/src/features/background-agent/subagent-spawn-limits.ts +++ b/src/features/background-agent/subagent-spawn-limits.ts @@ -2,7 +2,6 @@ import type { BackgroundTaskConfig } from "../../config/schema" import type { OpencodeClient } from "./constants" export const DEFAULT_MAX_SUBAGENT_DEPTH = 3 -export const DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET = 50 export interface SubagentSpawnContext { rootSessionID: string @@ -14,10 +13,6 @@ export function getMaxSubagentDepth(config?: BackgroundTaskConfig): number { return config?.maxDepth ?? DEFAULT_MAX_SUBAGENT_DEPTH } -export function getMaxRootSessionSpawnBudget(config?: BackgroundTaskConfig): number { - return config?.maxDescendants ?? DEFAULT_MAX_ROOT_SESSION_SPAWN_BUDGET -} - export async function resolveSubagentSpawnContext( client: OpencodeClient, parentSessionID: string, @@ -53,7 +48,7 @@ export async function resolveSubagentSpawnContext( } catch (error) { const reason = error instanceof Error ? error.message : String(error) throw new Error( - `Subagent spawn blocked: failed to resolve session lineage for ${parentSessionID}, so background_task.maxDescendants cannot be enforced safely. ${reason}` + `Subagent spawn blocked: failed to resolve session lineage for ${parentSessionID}, so background_task.maxDepth cannot be enforced safely. ${reason}` ) } @@ -84,14 +79,3 @@ export function createSubagentDepthLimitError(input: { `Subagent spawn blocked: child depth ${childDepth} exceeds background_task.maxDepth=${maxDepth}. Parent session: ${parentSessionID}. Root session: ${rootSessionID}. Continue in an existing subagent session instead of spawning another.` ) } - -export function createSubagentDescendantLimitError(input: { - rootSessionID: string - descendantCount: number - maxDescendants: number -}): Error { - const { rootSessionID, descendantCount, maxDescendants } = input - return new Error( - `Subagent spawn blocked: root session ${rootSessionID} already has ${descendantCount} descendants, which meets background_task.maxDescendants=${maxDescendants}. Reuse an existing session instead of spawning another.` - ) -} diff --git a/src/features/background-agent/task-poller.test.ts b/src/features/background-agent/task-poller.test.ts index 1811051c5..532fd6e57 100644 --- a/src/features/background-agent/task-poller.test.ts +++ b/src/features/background-agent/task-poller.test.ts @@ -648,7 +648,7 @@ describe("checkAndInterruptStaleTasks", () => { const task = createRunningTask({ startedAt: new Date(Date.now() - 15 * 60 * 1000), progress: undefined, - concurrencyKey: "anthropic/claude-opus-4-6", + concurrencyKey: "anthropic/claude-opus-4-7", }) //#when @@ -661,7 +661,7 @@ describe("checkAndInterruptStaleTasks", () => { }) //#then - expect(releaseMock).toHaveBeenCalledWith("anthropic/claude-opus-4-6") + expect(releaseMock).toHaveBeenCalledWith("anthropic/claude-opus-4-7") expect(task.concurrencyKey).toBeUndefined() }) diff --git a/src/features/background-agent/wait-for-task-session.test.ts b/src/features/background-agent/wait-for-task-session.test.ts new file mode 100644 index 000000000..812d9f700 --- /dev/null +++ b/src/features/background-agent/wait-for-task-session.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, test } from "bun:test" + +import type { BackgroundTaskStatus } from "./types" +import { waitForTaskSessionID } from "./wait-for-task-session" + +interface TaskSnapshot { + sessionID?: string + status?: BackgroundTaskStatus +} + +function createManager(responses: TaskSnapshot[]) { + let index = 0 + + return { + getTask(_taskID: string): TaskSnapshot { + const response = responses[Math.min(index, responses.length - 1)] + index += 1 + return response + }, + } +} + +describe("waitForTaskSessionID", () => { + test("#given task already has a session id #when waiting #then it returns immediately", async () => { + // given + const manager = createManager([{ sessionID: "ses_ready_123", status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_ready") + + // then + expect(sessionID).toBe("ses_ready_123") + }) + + test("#given session appears later #when waiting #then it polls until resolved", async () => { + // given + const manager = createManager([ + { status: "running" }, + { status: "running" }, + { sessionID: "ses_late_123", status: "running" }, + ]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_late", { + intervalMs: 1, + timeoutMs: 20, + }) + + // then + expect(sessionID).toBe("ses_late_123") + }) + + test("#given aborted signal #when waiting #then it returns undefined", async () => { + // given + const controller = new AbortController() + controller.abort() + const manager = createManager([{ status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_abort", { + signal: controller.signal, + }) + + // then + expect(sessionID).toBeUndefined() + }) + + test("#given task never resolves #when waiting past timeout #then it returns undefined", async () => { + // given + const manager = createManager([{ status: "running" }, { status: "running" }, { status: "running" }]) + + // when + const sessionID = await waitForTaskSessionID(manager, "bg_timeout", { + intervalMs: 1, + timeoutMs: 3, + }) + + // then + expect(sessionID).toBeUndefined() + }) + + test.each(["error", "cancelled", "interrupt"] satisfies BackgroundTaskStatus[])( + "#given %s task state #when waiting #then it returns undefined", + async (status: BackgroundTaskStatus) => { + // given + const manager = createManager([{ status }]) + + // when + const sessionID = await waitForTaskSessionID(manager, `bg_${status}`) + + // then + expect(sessionID).toBeUndefined() + } + ) +}) diff --git a/src/features/background-agent/wait-for-task-session.ts b/src/features/background-agent/wait-for-task-session.ts new file mode 100644 index 000000000..eb5fe49d8 --- /dev/null +++ b/src/features/background-agent/wait-for-task-session.ts @@ -0,0 +1,68 @@ +import { getTimingConfig } from "../../tools/delegate-task/timing" +import type { BackgroundTaskStatus } from "./types" + +type SessionWaitTerminalStatus = Extract +type AbortSignalLike = { aborted: boolean } + +interface TaskReader { + getTask(taskID: string): { sessionID?: string; status?: BackgroundTaskStatus } | undefined +} + +export interface WaitForTaskSessionIDOptions { + timeoutMs?: number + intervalMs?: number + signal?: AbortSignalLike +} + +function isTerminalStatus(status: BackgroundTaskStatus | undefined): status is SessionWaitTerminalStatus { + return status === "error" || status === "cancelled" || status === "interrupt" +} + +function waitForInterval(intervalMs: number): Promise { + return new Promise(resolve => { + const scheduler = globalThis as { setTimeout: (handler: () => void, timeout?: number) => unknown } + scheduler.setTimeout(resolve, intervalMs) + }) +} + +export async function waitForTaskSessionID( + manager: TaskReader, + taskID: string, + options: WaitForTaskSessionIDOptions = {} +): Promise { + const timing = getTimingConfig() + const timeoutMs = options.timeoutMs ?? timing.WAIT_FOR_SESSION_TIMEOUT_MS + const intervalMs = options.intervalMs ?? timing.WAIT_FOR_SESSION_INTERVAL_MS + + if (options.signal?.aborted) { + return undefined + } + + const initialTask = manager.getTask(taskID) + if (initialTask?.sessionID) { + return initialTask.sessionID + } + if (isTerminalStatus(initialTask?.status)) { + return undefined + } + + const deadline = Date.now() + timeoutMs + + while (Date.now() < deadline) { + if (options.signal?.aborted) { + return undefined + } + + await waitForInterval(intervalMs) + + const task = manager.getTask(taskID) + if (task?.sessionID) { + return task.sessionID + } + if (isTerminalStatus(task?.status)) { + return undefined + } + } + + return undefined +} diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts index b5f1983a9..97693761f 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.test.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.test.ts @@ -23,8 +23,8 @@ describe("mapClaudeModelToOpenCode", () => { expect(mapClaudeModelToOpenCode("sonnet")).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-6" }) }) - it("#when called with opus #then maps to anthropic claude-opus-4-6 object", () => { - expect(mapClaudeModelToOpenCode("opus")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + it("#when called with opus #then maps to anthropic claude-opus-4-7 object", () => { + expect(mapClaudeModelToOpenCode("opus")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) it("#when called with haiku #then maps to anthropic claude-haiku-4-5 object", () => { @@ -47,8 +47,8 @@ describe("mapClaudeModelToOpenCode", () => { expect(mapClaudeModelToOpenCode("claude-sonnet-4-5-20250514")).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-5-20250514" }) }) - it("#when called with claude-opus-4-6 #then adds anthropic object format", () => { - expect(mapClaudeModelToOpenCode("claude-opus-4-6")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + it("#when called with claude-opus-4-7 #then adds anthropic object format", () => { + expect(mapClaudeModelToOpenCode("claude-opus-4-7")).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) it("#when called with claude-haiku-4-5-20251001 #then adds anthropic object format", () => { diff --git a/src/features/claude-code-agent-loader/claude-model-mapper.ts b/src/features/claude-code-agent-loader/claude-model-mapper.ts index 736a5f303..7737de5f7 100644 --- a/src/features/claude-code-agent-loader/claude-model-mapper.ts +++ b/src/features/claude-code-agent-loader/claude-model-mapper.ts @@ -5,7 +5,7 @@ const ANTHROPIC_PREFIX = "anthropic/" const CLAUDE_CODE_ALIAS_MAP = new Map([ ["sonnet", `${ANTHROPIC_PREFIX}claude-sonnet-4-6`], - ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-6`], + ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-7`], ["haiku", `${ANTHROPIC_PREFIX}claude-haiku-4-5`], ]) diff --git a/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts b/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts index e90bc2519..1e1fce79a 100644 --- a/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts +++ b/src/features/claude-code-agent-loader/opencode-config-agents-reader.test.ts @@ -38,7 +38,7 @@ describe("readOpencodeConfigAgents", () => { agents: { "my-agent": { description: "Custom agent", - model: "claude-opus-4-6", + model: "claude-opus-4-7", mode: "subagent", prompt: "You are a helpful assistant", }, diff --git a/src/features/claude-code-command-loader/loader-cache.ts b/src/features/claude-code-command-loader/loader-cache.ts new file mode 100644 index 000000000..9f0d4d195 --- /dev/null +++ b/src/features/claude-code-command-loader/loader-cache.ts @@ -0,0 +1,37 @@ +import { promises as fs } from "fs" +import { resolve } from "path" + +import type { CommandDefinition } from "./types" + +const commandLoaderCache = new Map>>() + +export async function getCommandLoaderCacheKey(directory?: string): Promise { + const resolvedDirectory = resolve(directory ?? process.cwd()) + + try { + return await fs.realpath(resolvedDirectory) + } catch { + return resolvedDirectory + } +} + +export function getCachedCommands( + cacheKey: string, +): Promise> | undefined { + return commandLoaderCache.get(cacheKey) +} + +export function setCachedCommands( + cacheKey: string, + commands: Promise>, +): void { + commandLoaderCache.set(cacheKey, commands) +} + +export function deleteCachedCommands(cacheKey: string): void { + commandLoaderCache.delete(cacheKey) +} + +export function clearCommandLoaderCache(): void { + commandLoaderCache.clear() +} diff --git a/src/features/claude-code-command-loader/loader.test.ts b/src/features/claude-code-command-loader/loader.test.ts index be7928d3f..b674f8ff9 100644 --- a/src/features/claude-code-command-loader/loader.test.ts +++ b/src/features/claude-code-command-loader/loader.test.ts @@ -1,9 +1,10 @@ import { execFileSync } from "node:child_process" -import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { promises as fs } from "node:fs" +import { afterEach, beforeEach, describe, expect, it, spyOn } 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" +import * as loader from "./loader" const TEST_DIR = join(tmpdir(), `claude-code-command-loader-${Date.now()}`) @@ -16,19 +17,41 @@ function writeCommand(directory: string, name: string, description: string): voi } describe("claude-code command loader", () => { + let originalClaudeConfigDir: string | undefined let originalOpencodeConfigDir: string | undefined beforeEach(() => { mkdirSync(TEST_DIR, { recursive: true }) + originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR originalOpencodeConfigDir = process.env.OPENCODE_CONFIG_DIR + + const claudeConfigDir = join(TEST_DIR, "claude-config") + const opencodeConfigDir = join(TEST_DIR, "opencode-config") + process.env.CLAUDE_CONFIG_DIR = claudeConfigDir + process.env.OPENCODE_CONFIG_DIR = opencodeConfigDir + + if ("clearCommandLoaderCache" in loader && typeof loader.clearCommandLoaderCache === "function") { + loader.clearCommandLoaderCache() + } }) afterEach(() => { + if (originalClaudeConfigDir === undefined) { + delete process.env.CLAUDE_CONFIG_DIR + } else { + process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir + } + if (originalOpencodeConfigDir === undefined) { delete process.env.OPENCODE_CONFIG_DIR } else { process.env.OPENCODE_CONFIG_DIR = originalOpencodeConfigDir } + + if ("clearCommandLoaderCache" in loader && typeof loader.clearCommandLoaderCache === "function") { + loader.clearCommandLoaderCache() + } + rmSync(TEST_DIR, { recursive: true, force: true }) }) @@ -39,7 +62,7 @@ describe("claude-code command loader", () => { writeCommand(join(projectDir, ".opencode", "commands"), "ancestor", "Ancestor command") // when - const commands = await loadOpencodeProjectCommands(childDir) + const commands = await loader.loadOpencodeProjectCommands(childDir) // then expect(commands.ancestor?.description).toBe("(opencode-project) Ancestor command") @@ -50,7 +73,7 @@ describe("claude-code command loader", () => { writeCommand(join(TEST_DIR, ".opencode", "command"), "singular", "Singular command") // when - const commands = await loadOpencodeProjectCommands(TEST_DIR) + const commands = await loader.loadOpencodeProjectCommands(TEST_DIR) // then expect(commands.singular?.description).toBe("(opencode-project) Singular command") @@ -66,7 +89,7 @@ describe("claude-code command loader", () => { writeCommand(projectDir, "duplicate", "Nearest command") // when - const commands = await loadOpencodeProjectCommands(childDir) + const commands = await loader.loadOpencodeProjectCommands(childDir) // then expect(commands.duplicate?.description).toBe("(opencode-project) Nearest command") @@ -79,7 +102,7 @@ describe("claude-code command loader", () => { writeCommand(join(opencodeConfigDir, "commands"), "global-plural", "Global plural command") // when - const commands = await loadOpencodeGlobalCommands() + const commands = await loader.loadOpencodeGlobalCommands() // then expect(commands["global-plural"]?.description).toBe("(opencode) Global plural command") @@ -94,7 +117,7 @@ describe("claude-code command loader", () => { writeCommand(join(profileConfigDir, "commands"), "duplicate-global", "Profile global command") // when - const commands = await loadOpencodeGlobalCommands() + const commands = await loader.loadOpencodeGlobalCommands() // then expect(commands["duplicate-global"]?.description).toBe("(opencode) Profile global command") @@ -114,7 +137,7 @@ describe("claude-code command loader", () => { writeCommand(join(TEST_DIR, ".opencode", "commands"), "outside", "Outside command") // when - const commands = await loadOpencodeProjectCommands(nestedDirectory) + const commands = await loader.loadOpencodeProjectCommands(nestedDirectory) // then expect(commands["deploy/staging"]?.description).toBe("(opencode-project) Deploy staging") @@ -122,4 +145,38 @@ describe("claude-code command loader", () => { expect(commands.outside).toBeUndefined() expect(commands["deploy:staging"]).toBeUndefined() }) + + it("#given commands nested under an excluded basename #when loadProjectCommands is called #then it skips the excluded directory contents", async () => { + // given + writeCommand(join(TEST_DIR, ".claude", "commands"), "real", "Real command") + writeCommand( + join(TEST_DIR, ".claude", "commands", "node_modules"), + "fake", + "Fake command", + ) + + // when + const commands = await loader.loadProjectCommands(TEST_DIR) + + // then + expect(commands.real?.description).toBe("(project) Real command") + expect(commands.fake).toBeUndefined() + }) + + it("#given a previously loaded directory #when loadAllCommands is called twice #then the second call reuses the cached result without readdir calls", async () => { + // given + writeCommand(join(TEST_DIR, ".claude", "commands"), "cached", "Cached command") + const readdirSpy = spyOn(fs, "readdir") + + // when + const firstCommands = await loader.loadAllCommands(TEST_DIR) + const firstReaddirCount = readdirSpy.mock.calls.length + const secondCommands = await loader.loadAllCommands(TEST_DIR) + + // then + expect(firstCommands.cached?.description).toBe("(project) Cached command") + expect(secondCommands).toEqual(firstCommands) + expect(firstReaddirCount).toBeGreaterThan(0) + expect(readdirSpy.mock.calls.length).toBe(firstReaddirCount) + }) }) diff --git a/src/features/claude-code-command-loader/loader.ts b/src/features/claude-code-command-loader/loader.ts index b052f56bd..6ee178b66 100644 --- a/src/features/claude-code-command-loader/loader.ts +++ b/src/features/claude-code-command-loader/loader.ts @@ -4,13 +4,23 @@ import { parseFrontmatter } from "../../shared/frontmatter" import { sanitizeModelField } from "../../shared/model-sanitizer" import { isMarkdownFile } from "../../shared/file-utils" import { + EXCLUDED_DIRS, findProjectOpencodeCommandDirs, getClaudeConfigDir, getOpenCodeCommandDirs, } from "../../shared" import { log } from "../../shared/logger" +import { + clearCommandLoaderCache, + deleteCachedCommands, + getCachedCommands, + getCommandLoaderCacheKey, + setCachedCommands, +} from "./loader-cache" import type { CommandScope, CommandDefinition, CommandFrontmatter, LoadedCommand } from "./types" +export { clearCommandLoaderCache } + async function loadCommandsFromDir( commandsDir: string, scope: CommandScope, @@ -48,6 +58,7 @@ async function loadCommandsFromDir( for (const entry of entries) { if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue if (entry.name.startsWith(".")) continue const subDirPath = join(commandsDir, entry.name) const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name @@ -159,11 +170,26 @@ export async function loadOpencodeProjectCommands(directory?: string): Promise> { - const [user, project, global, projectOpencode] = await Promise.all([ + const cacheKey = await getCommandLoaderCacheKey(directory) + const cachedCommands = getCachedCommands(cacheKey) + if (cachedCommands) { + return cachedCommands + } + + const loadCommandsPromise = Promise.all([ loadUserCommands(), loadProjectCommands(directory), loadOpencodeGlobalCommands(), loadOpencodeProjectCommands(directory), ]) - return { ...projectOpencode, ...global, ...project, ...user } + .then(([user, project, global, projectOpencode]) => { + return { ...projectOpencode, ...global, ...project, ...user } + }) + .catch((error) => { + deleteCachedCommands(cacheKey) + throw error + }) + + setCachedCommands(cacheKey, loadCommandsPromise) + return loadCommandsPromise } diff --git a/src/features/claude-code-mcp-loader/AGENTS.md b/src/features/claude-code-mcp-loader/AGENTS.md new file mode 100644 index 000000000..593ca22de --- /dev/null +++ b/src/features/claude-code-mcp-loader/AGENTS.md @@ -0,0 +1,78 @@ +# src/features/claude-code-mcp-loader/ — Tier 2 MCP Loader (.mcp.json) + +**Generated:** 2026-04-18 + +## OVERVIEW + +11 files. Loads `.mcp.json` files from project/user scopes and expands `${VAR}` env vars. Feeds Tier 2 of the 3-tier MCP system into `mcp-config-handler.ts` during Phase 5 of config loading. + +## WHY IT EXISTS + +Claude Code ecosystem ships MCPs via `.mcp.json` files with `${VAR}` env var placeholders. OmO consumes these unchanged so existing Claude Code MCP configs work. + +## LOAD PIPELINE + +``` +loadMcpConfigs(ctx) + → scope-filter.ts: discover .mcp.json at project + user scopes + → loader.ts: parse JSON + → env-expander.ts: replace ${VAR} with process.env[VAR] + → transformer.ts: map Claude Code format → OpenCode McpLocal / McpRemote shape + → return LoadedMcpServer[] +``` + +## MCP FORMAT + +```jsonc +// .mcp.json +{ + "mcpServers": { + "my-stdio": { + "type": "stdio", + "command": "node", + "args": ["server.js"], + "env": { + "API_KEY": "${MY_API_KEY}" + } + }, + "my-http": { + "type": "http", // "sse" legacy → mapped to http + "url": "https://example.com/mcp", + "headers": { + "Authorization": "Bearer ${MY_TOKEN}" + } + } + } +} +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | Barrel: `loadMcpConfigs`, types | +| `loader.ts` | `loadMcpConfigs()` main entry | +| `types.ts` | `ClaudeCodeMcpServer`, `LoadedMcpServer`, `McpScope` | +| `env-expander.ts` | `expandEnvVarsInObject()` — recursive `${VAR}` substitution | +| `transformer.ts` | Claude Code format → OpenCode `Mcp` shape | +| `scope-filter.ts` | Project vs user scope precedence | + +## THREE-TIER MCP CONTEXT + +| Tier | Loader | Scope | +|------|--------|-------| +| 1. Built-in | `src/mcp/` `createBuiltinMcps()` | Global, 3 remote HTTP MCPs | +| 2. **Claude Code** | **This module** | **From `.mcp.json`, project + user** | +| 3. Skill-embedded | `src/features/skill-mcp-manager/` | Per-session, from SKILL.md YAML | + +## SECURITY + +- **Env var allowlist**: `mcp_env_allowlist` config restricts which env vars can be expanded +- **No shell execution**: `${VAR}` is string replacement only, not shell `$()` +- **Secrets redaction**: `env-cleaner.ts` (in skill-mcp-manager) filters known secret patterns from logs + +## RELATED + +- Phase 5 integration: `src/plugin-handlers/mcp-config-handler.ts` +- Skill-embedded MCPs (Tier 3): `src/features/skill-mcp-manager/` +- Built-in MCPs (Tier 1): `src/mcp/` diff --git a/src/features/claude-code-plugin-loader/AGENTS.md b/src/features/claude-code-plugin-loader/AGENTS.md new file mode 100644 index 000000000..ae6cd3158 --- /dev/null +++ b/src/features/claude-code-plugin-loader/AGENTS.md @@ -0,0 +1,78 @@ +# src/features/claude-code-plugin-loader/ — Unified Claude Code Plugin Loader + +**Generated:** 2026-04-18 + +## OVERVIEW + +16 files. Full Claude Code plugin compatibility layer. Discovers and loads ALL plugin components (commands, agents, skills, hooks, MCP servers, LSP servers) from `.opencode/plugins/` and `~/.claude/plugins/`. + +## WHY IT EXISTS + +Claude Code plugins ship commands/agents/skills as separate files with `plugin.json` manifest. OmO uses this loader to ingest them into its own registry so existing Claude Code plugins work unchanged under OmO. + +## LOAD PIPELINE + +``` +loadAllPluginComponents(ctx) + → discoverPlugins() # scan .opencode/plugins + ~/.claude/plugins + → readPluginManifest(plugin.json) # parse name/version/commands/agents/skills/hooks/mcpServers + → loadPluginCommands() + → loadPluginAgents() + → loadPluginSkills() + → loadPluginHooks() # register hook handlers + → loadPluginMcpServers() # feed into mcp-config-handler (tier 2) + → loadPluginLspServers() + → return LoadedPluginBundle +``` + +Called from `src/plugin-handlers/plugin-components-loader.ts` during Phase 2 of config handler (10s timeout with error isolation — one broken plugin does not sink the plugin load). + +## KEY FILES + +| File | Purpose | +|------|---------| +| `index.ts` | Barrel: `loadAllPluginComponents`, `PluginManifest`, `ClaudeSettings` types | +| `plugin-discovery.ts` | Find plugin directories across scopes | +| `plugin-manifest-parser.ts` | Parse `plugin.json` with Zod validation | +| `command-loader.ts` | Load commands from `commands/` or `COMMANDS.md` | +| `agent-loader.ts` | Load agents from `agents/` or `AGENTS.md` frontmatter | +| `skill-loader.ts` | Load skills from `skills/` or `SKILL.md` | +| `hook-loader.ts` | Load hooks config from `hooks/` or manifest | +| `mcp-loader.ts` | Extract MCP server configs | +| `lsp-loader.ts` | Extract LSP server configs | +| `settings-loader.ts` | Parse Claude Code `settings.json` | + +## PLUGIN MANIFEST (plugin.json) + +```jsonc +{ + "name": "my-plugin", + "version": "1.0.0", + "description": "...", + "commands": ["./commands"], // or string[] of paths + "agents": ["./agents"], + "skills": ["./skills"], + "hooks": "./hooks/config.json", + "mcpServers": "./.mcp.json", + "lspServers": "./lsp" +} +``` + +## SCOPES + +| Scope | Path | Priority | +|-------|------|----------| +| `project` | `.opencode/plugins/` | Highest | +| `local` | `~/.opencode/plugins/` | Medium | +| `user` | `~/.claude/plugins/` | Medium | +| `managed` | Built-in | Lowest | + +## ERROR ISOLATION + +Each plugin loads in isolation — if one fails (bad manifest, missing file, syntax error), others still load. Errors surface as warnings in `bunx oh-my-opencode doctor`. + +## RELATED + +- Phase 2 loader: `src/plugin-handlers/plugin-components-loader.ts` +- Tier 2 MCP integration: `src/features/claude-code-mcp-loader/` +- Claude Code compat hooks: `src/hooks/claude-code-hooks/` diff --git a/src/features/opencode-skill-loader/skill-content.test.ts b/src/features/opencode-skill-loader/skill-content.test.ts index 64d6d5bf4..dedf74413 100644 --- a/src/features/opencode-skill-loader/skill-content.test.ts +++ b/src/features/opencode-skill-loader/skill-content.test.ts @@ -3,12 +3,19 @@ import { describe, it, expect, beforeEach, afterEach } from "bun:test" import { join } from "node:path" import { tmpdir } from "node:os" -import { resolveSkillContent, resolveMultipleSkills, resolveSkillContentAsync, resolveMultipleSkillsAsync } from "./skill-content" +import { + clearSkillCache, + resolveSkillContent, + resolveMultipleSkills, + resolveSkillContentAsync, + resolveMultipleSkillsAsync, +} from "./skill-content" let originalEnv: Record let testConfigDir: string beforeEach(() => { + clearSkillCache() originalEnv = { CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR, OPENCODE_CONFIG_DIR: process.env.OPENCODE_CONFIG_DIR, @@ -20,6 +27,7 @@ beforeEach(() => { }) afterEach(() => { + clearSkillCache() for (const [key, value] of Object.entries(originalEnv)) { if (value !== undefined) { process.env[key] = value diff --git a/src/features/task-toast-manager/manager.test.ts b/src/features/task-toast-manager/manager.test.ts index d99698347..92ab524a0 100644 --- a/src/features/task-toast-manager/manager.test.ts +++ b/src/features/task-toast-manager/manager.test.ts @@ -203,7 +203,7 @@ describe("TaskToastManager", () => { description: "Task with inherited model", agent: "sisyphus-junior", isBackground: false, - modelInfo: { model: "cliproxy/claude-opus-4-6", type: "inherited" as const }, + modelInfo: { model: "cliproxy/claude-opus-4-7", type: "inherited" as const }, } // when - addTask is called @@ -213,7 +213,7 @@ describe("TaskToastManager", () => { expect(mockClient.tui.showToast).toHaveBeenCalled() const call = mockClient.tui.showToast.mock.calls[0][0] expect(call.body.message).toContain("[FALLBACK]") - expect(call.body.message).toContain("cliproxy/claude-opus-4-6") + expect(call.body.message).toContain("cliproxy/claude-opus-4-7") expect(call.body.message).toContain("(inherited from parent)") }) diff --git a/src/features/team-mode/index.ts b/src/features/team-mode/index.ts new file mode 100644 index 000000000..6aa6742a6 --- /dev/null +++ b/src/features/team-mode/index.ts @@ -0,0 +1,2 @@ +export * from "./types" +export * from "./team-worktree" diff --git a/src/features/team-mode/team-layout-tmux/index.ts b/src/features/team-mode/team-layout-tmux/index.ts new file mode 100644 index 000000000..8858d5a4b --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/index.ts @@ -0,0 +1 @@ +export { canVisualize, createTeamLayout, removeTeamLayout } from "./layout" diff --git a/src/features/team-mode/team-layout-tmux/layout.test.ts b/src/features/team-mode/team-layout-tmux/layout.test.ts new file mode 100644 index 000000000..aa9a90ff5 --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/layout.test.ts @@ -0,0 +1,94 @@ +import { beforeEach, describe, expect, mock, test } from "bun:test" + +type LayoutModule = typeof import("./layout") + +const spawnMock = mock(() => ({ + exited: Promise.resolve(0), + stdout: new ReadableStream({ start(controller) { controller.enqueue(new TextEncoder().encode("%1\n")); controller.close() } }), + stderr: new ReadableStream({ start(controller) { controller.close() } }), +})) + +const layoutSpecifier = import.meta.resolve("./layout") +const spawnProcessSpecifier = import.meta.resolve("../../../shared/tmux/tmux-utils/spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") +const sharedSpecifier = import.meta.resolve("../../../shared") + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: mock(() => Promise.resolve("tmux")) })) + mock.module(sharedSpecifier, () => ({ log: mock(() => undefined) })) +} + +async function loadLayoutModule(): Promise { + const module = await import(`${layoutSpecifier}?test=${crypto.randomUUID()}`) + return module as LayoutModule +} + +describe("team-layout-tmux", () => { + beforeEach(() => { + registerModuleMocks() + spawnMock.mockClear() + process.env.TMUX = "/tmp/tmux-1" + }) + + test("returns null and makes no tmux calls when visualization unavailable", async () => { + // given + delete process.env.TMUX + const { createTeamLayout, canVisualize } = await loadLayoutModule() + + // when + const result = await createTeamLayout("run-1", [], {} as never) + + // then + expect(canVisualize()).toBe(false) + expect(result).toBeNull() + expect(spawnMock).toHaveBeenCalledTimes(0) + }) + + test("creates focus and grid windows", async () => { + // given + const { createTeamLayout } = await loadLayoutModule() + const members = [ + { name: "lead", sessionId: "s1", color: "red" }, + { name: "m2", sessionId: "s2" }, + { name: "m3", sessionId: "s3" }, + ] + + // when + await createTeamLayout("run-2", members, {} as never) + + // then + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("new-session") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("new-window") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("split-window") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("select-layout") + expect(spawnMock.mock.calls.flatMap((call) => call[0] as Array)).toContain("select-pane") + }) + + test("returns null when tmux command fails", async () => { + // given + const { createTeamLayout } = await loadLayoutModule() + spawnMock.mockImplementationOnce(() => ({ + exited: Promise.resolve(1), + stdout: new ReadableStream({ start(controller) { controller.close() } }), + stderr: new ReadableStream({ start(controller) { controller.close() } }), + })) + + // when + const result = await createTeamLayout("run-3", [{ name: "lead", sessionId: "s1" }], {} as never) + + // then + expect(result).toBeNull() + }) + + test("cleans up the tmux session", async () => { + // given + const { removeTeamLayout } = await loadLayoutModule() + + // when + await removeTeamLayout("run-4", {} as never) + + // then + expect(spawnMock.mock.calls.some((call) => (call[0] as Array).includes("kill-session"))).toBe(true) + }) +}) diff --git a/src/features/team-mode/team-layout-tmux/layout.ts b/src/features/team-mode/team-layout-tmux/layout.ts new file mode 100644 index 000000000..f414ccbfe --- /dev/null +++ b/src/features/team-mode/team-layout-tmux/layout.ts @@ -0,0 +1,120 @@ +import { spawn } from "../../../shared/tmux/tmux-utils/spawn-process" +import { log } from "../../../shared" +import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver" +import type { TmuxSessionManager } from "../../tmux-subagent/manager" + +type TeamLayoutMember = { name: string; sessionId: string; color?: string } + +type TeamLayoutResult = { + focusWindowId: string + gridWindowId: string + panesByMember: Record +} + +export function canVisualize(): boolean { + return process.env.TMUX !== undefined +} + +async function runTmux(tmuxPath: string, args: Array): Promise<{ success: boolean; output: string }> { + const proc = spawn([tmuxPath, ...args], { stdout: "pipe", stderr: "pipe" }) + const outputPromise = new Response(proc.stdout).text() + const exitCode = await proc.exited + const output = await outputPromise + + if (exitCode !== 0) { + return { success: false, output: output.trim() } + } + + return { success: true, output: output.trim() } +} + +async function createWindow( + tmuxPath: string, + sessionName: string, + windowName: string, + layout: "main-vertical" | "tiled", + members: Array, +): Promise<{ windowId: string; panesByMember: Record } | null> { + const base = await runTmux(tmuxPath, ["new-window", "-d", "-P", "-F", "#{window_id}", "-t", sessionName, "-n", windowName]) + if (!base.success || !base.output) return null + + const panesByMember: Record = {} + const [lead, ...rest] = members + if (!lead) return null + + const leadPane = await runTmux(tmuxPath, ["list-panes", "-t", `${sessionName}:${base.output}`, "-F", "#{pane_id}"]) + if (!leadPane.success || !leadPane.output) return null + panesByMember[lead.name] = leadPane.output.split("\n")[0] ?? "" + + for (const member of rest) { + const split = await runTmux(tmuxPath, ["split-window", "-d", "-P", "-F", "#{pane_id}", "-t", panesByMember[lead.name] ?? base.output, "sh", "-c", "cat >/dev/null"]) + if (!split.success || !split.output) return null + panesByMember[member.name] = split.output + } + + const layoutResult = await runTmux(tmuxPath, ["select-layout", "-t", `${sessionName}:${base.output}`, layout]) + if (!layoutResult.success) return null + + for (const member of members) { + const paneId = panesByMember[member.name] + if (!paneId) return null + const label = member.color ? `${member.name} ${member.color}` : member.name + const titleResult = await runTmux(tmuxPath, ["select-pane", "-t", paneId, "-T", label]) + if (!titleResult.success) return null + await runTmux(tmuxPath, ["set-option", "-t", paneId, "pane-border-status", "top"]) + await runTmux(tmuxPath, ["set-option", "-t", paneId, "pane-border-format", `#{pane_title} ${label}`]) + await runTmux(tmuxPath, ["pipe-pane", "-I", "-t", paneId, "cat >/dev/null"]) + } + + return { windowId: base.output, panesByMember } +} + +export async function createTeamLayout( + teamRunId: string, + members: Array, + tmuxMgr: TmuxSessionManager, +): Promise { + if (!canVisualize()) { + log("tmux visualization unavailable, skipping") + return null + } + + try { + void tmuxMgr + const tmuxPath = await getTmuxPath() + if (!tmuxPath) { + log("tmux visualization unavailable, skipping") + return null + } + + const sessionName = `omo-team-${teamRunId}` + const created = await runTmux(tmuxPath, ["new-session", "-d", "-s", sessionName, "-P", "-F", "#{window_id}"]) + if (!created.success || !created.output) return null + + const focus = await createWindow(tmuxPath, sessionName, "focus", "main-vertical", members) + const grid = await createWindow(tmuxPath, sessionName, "grid", "tiled", members) + if (!focus || !grid) return null + + return { + focusWindowId: focus.windowId, + gridWindowId: grid.windowId, + panesByMember: focus.panesByMember, + } + } catch (error) { + log("tmux visualization unavailable, skipping", { error: String(error) }) + return null + } +} + +export async function removeTeamLayout(teamRunId: string, tmuxMgr: TmuxSessionManager): Promise { + void tmuxMgr + if (!canVisualize()) return + + try { + const tmuxPath = await getTmuxPath() + if (!tmuxPath) return + await runTmux(tmuxPath, ["kill-session", "-t", `omo-team-${teamRunId}`]) + } catch { + return + } +} diff --git a/src/features/team-mode/team-worktree/cleanup.test.ts b/src/features/team-mode/team-worktree/cleanup.test.ts new file mode 100644 index 000000000..f47c63af9 --- /dev/null +++ b/src/features/team-mode/team-worktree/cleanup.test.ts @@ -0,0 +1,31 @@ +/// + +import { afterAll, expect, test } from "bun:test" +import fs from "node:fs/promises" +import os from "node:os" +import path from "node:path" + +import { findOrphanWorktrees } from "./cleanup" + +const temporaryDirectories: string[] = [] + +afterAll(async () => { + for (const directory of temporaryDirectories) { + await fs.rm(directory, { recursive: true, force: true }) + } +}) + +test("given runtime mismatch when findOrphanWorktrees then returns orphan paths", async () => { + // given + const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "team-worktree-orphans-")) + temporaryDirectories.push(baseDir) + await fs.mkdir(path.join(baseDir, "worktrees", "t1", "m1"), { recursive: true }) + await fs.mkdir(path.join(baseDir, "runtime", "t1"), { recursive: true }) + await fs.writeFile(path.join(baseDir, "runtime", "t1", "state.json"), JSON.stringify({ status: "deleted" })) + + // when + const result = await findOrphanWorktrees(baseDir, {}) + + // then + expect(result).toEqual([path.join(baseDir, "worktrees", "t1", "m1")]) +}) diff --git a/src/features/team-mode/team-worktree/cleanup.ts b/src/features/team-mode/team-worktree/cleanup.ts new file mode 100644 index 000000000..673ecebc1 --- /dev/null +++ b/src/features/team-mode/team-worktree/cleanup.ts @@ -0,0 +1,77 @@ +import fs from "node:fs/promises" +import path from "node:path" + +import type { TeamModeConfig } from "./manager" + +async function runGit(args: string[]): Promise<{ code: number; stderr: string }> { + const process = Bun.spawn({ cmd: ["git", ...args], stdout: "pipe", stderr: "pipe" }) + const [exitCode, stderrText] = await Promise.all([process.exited, new Response(process.stderr).text()]) + return { code: exitCode, stderr: stderrText } +} + +export async function removeWorktree(worktreePath: string): Promise { + await fs.rm(worktreePath, { recursive: true, force: true }) + + const rootLookup = await Bun.spawn({ + cmd: ["git", "-C", worktreePath, "rev-parse", "--show-superproject-working-tree"], + stdout: "pipe", + stderr: "pipe", + }) + const [rootExitCode, rootStdout] = await Promise.all([ + rootLookup.exited, + new Response(rootLookup.stdout).text(), + new Response(rootLookup.stderr).text(), + ]) + const result = + rootExitCode === 0 && rootStdout.trim().length > 0 + ? await runGit(["-C", rootStdout.trim(), "worktree", "remove", "--force", worktreePath]) + : await runGit(["worktree", "remove", "--force", worktreePath]) + + if ( + result.code !== 0 && + !result.stderr.includes("not a worktree") && + !result.stderr.includes("not a working tree") && + !result.stderr.includes("already removed") + ) { + throw new Error(result.stderr.trim() || "git worktree remove failed") + } + + if (rootExitCode === 0 && rootStdout.trim().length > 0) { + await runGit(["-C", rootStdout.trim(), "worktree", "prune"]) + } +} + +export async function findOrphanWorktrees(baseDir: string, _config: TeamModeConfig): Promise { + const orphanWorktrees: string[] = [] + const worktreesDir = path.join(baseDir, "worktrees") + + let teamRunDirectories: string[] + try { + teamRunDirectories = await fs.readdir(worktreesDir) + } catch { + return orphanWorktrees + } + + for (const teamRunId of teamRunDirectories) { + const teamRunPath = path.join(worktreesDir, teamRunId) + const memberNames = await fs.readdir(teamRunPath).catch(() => []) + + for (const memberName of memberNames) { + const worktreePath = path.join(teamRunPath, memberName) + const statePath = path.join(baseDir, "runtime", teamRunId, "state.json") + + try { + const stateContents = await fs.readFile(statePath, "utf8") + const state = JSON.parse(stateContents) as { status?: string } + + if (state.status !== "active" && state.status !== "shutdown_requested") { + orphanWorktrees.push(worktreePath) + } + } catch { + orphanWorktrees.push(worktreePath) + } + } + } + + return orphanWorktrees +} diff --git a/src/features/team-mode/team-worktree/index.ts b/src/features/team-mode/team-worktree/index.ts new file mode 100644 index 000000000..e311ff757 --- /dev/null +++ b/src/features/team-mode/team-worktree/index.ts @@ -0,0 +1,2 @@ +export { GitUnavailableError, createWorktree, isGitAvailable, validateWorktreeSpec } from "./manager" +export { findOrphanWorktrees, removeWorktree } from "./cleanup" diff --git a/src/features/team-mode/team-worktree/manager.test.ts b/src/features/team-mode/team-worktree/manager.test.ts new file mode 100644 index 000000000..b1e98556b --- /dev/null +++ b/src/features/team-mode/team-worktree/manager.test.ts @@ -0,0 +1,104 @@ +/// + +import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test" +import { randomUUID } from "node:crypto" +import fs from "node:fs/promises" +import os from "node:os" +import path from "node:path" + +import { GitUnavailableError, createWorktree, setGitCommandRunnerForTests, validateWorktreeSpec } from "./manager" +import { removeWorktree } from "./cleanup" + +const temporaryDirectories: string[] = [] + +async function initGitRepo(): Promise { + const repositoryRoot = await fs.mkdtemp(path.join(os.tmpdir(), "team-worktree-")) + temporaryDirectories.push(repositoryRoot) + Bun.spawnSync(["git", "init"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + await fs.writeFile(path.join(repositoryRoot, "README.md"), "hello\n") + Bun.spawnSync(["git", "add", "README.md"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "config", "user.email", "test@example.com"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "config", "user.name", "Test User"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + Bun.spawnSync(["git", "commit", "-m", "init"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + return repositoryRoot +} + +beforeAll(() => { + mock.restore() +}) + +afterAll(async () => { + for (const directory of temporaryDirectories) { + await fs.rm(directory, { recursive: true, force: true }) + } + mock.restore() +}) + +describe("team-worktree manager", () => { + test("given tmp git repo when createWorktree then registers detached worktree", async () => { + // given + const repositoryRoot = await initGitRepo() + const worktreePath = `../worktree-${randomUUID()}` + const worktreeDirectory = path.resolve(repositoryRoot, worktreePath) + + // when + const resultPath = await createWorktree(repositoryRoot, "t1", "m1", worktreePath, {}) + + // then + expect(resultPath).toBe(worktreeDirectory) + await expect(fs.stat(worktreeDirectory)).resolves.toBeDefined() + const listResult = Bun.spawnSync(["git", "worktree", "list"], { cwd: repositoryRoot, stdout: "pipe", stderr: "pipe" }) + expect(new TextDecoder().decode(listResult.stdout)).toContain(worktreeDirectory) + const headResult = Bun.spawnSync(["git", "-C", worktreeDirectory, "rev-parse", "HEAD"], { stdout: "pipe", stderr: "pipe" }) + const repoHeadResult = Bun.spawnSync(["git", "-C", repositoryRoot, "rev-parse", "HEAD"], { stdout: "pipe", stderr: "pipe" }) + expect(new TextDecoder().decode(headResult.stdout).trim()).toBe(new TextDecoder().decode(repoHeadResult.stdout).trim()) + }) + + test("validateWorktreeSpec rejects bare name", () => { + // given + const worktreePath = "feature-x" + + // when + const validate = () => validateWorktreeSpec(worktreePath) + + // then + expect(validate).toThrow("worktreePath must be a filesystem path (relative './...', '../...' or absolute '/...')") + }) + + test("given git unavailable when createWorktree then throws unavailable error", async () => { + // given + const repositoryRoot = await initGitRepo() + setGitCommandRunnerForTests(async (args) => { + if (args[0] === "--version") { + return { code: 1, stderr: "git missing" } + } + + return { code: 0, stderr: "" } + }) + + // when + const create = createWorktree(repositoryRoot, "t1", "m1", `../worktree-${randomUUID()}`, {}) + + // then + await expect(create).rejects.toBeInstanceOf(GitUnavailableError) + setGitCommandRunnerForTests(async (args) => { + if (args[0] === "--version") { + return { code: 0, stderr: "" } + } + + return { code: 0, stderr: "" } + }) + }) + + test("given created worktree when removeWorktree then directory disappears", async () => { + // given + const repositoryRoot = await initGitRepo() + const worktreePath = await createWorktree(repositoryRoot, "t1", "m1", `../worktree-${randomUUID()}`, {}) + + // when + await removeWorktree(worktreePath) + + // then + await expect(fs.stat(worktreePath)).rejects.toThrow() + }) +}) diff --git a/src/features/team-mode/team-worktree/manager.ts b/src/features/team-mode/team-worktree/manager.ts new file mode 100644 index 000000000..359df4cd0 --- /dev/null +++ b/src/features/team-mode/team-worktree/manager.ts @@ -0,0 +1,62 @@ +import path from "node:path" + +export type TeamModeConfig = { + worktreeBaseDir?: string +} + +export class GitUnavailableError extends Error { + constructor() { + super("git required for worktree members") + this.name = "GitUnavailableError" + } +} + +function countParentSegments(spec: string): number { + return spec.split("/").filter((segment) => segment === "..").length +} + +async function runGit(args: string[], cwd?: string): Promise<{ code: number; stderr: string }> { + const process = Bun.spawn({ cmd: ["git", ...args], cwd, stdout: "pipe", stderr: "pipe" }) + const [exitCode, stderrBytes] = await Promise.all([process.exited, new Response(process.stderr).text()]) + return { code: exitCode, stderr: stderrBytes } +} + +let gitCommandRunner = runGit + +export function setGitCommandRunnerForTests(runner: typeof runGit): void { + gitCommandRunner = runner +} + +export async function isGitAvailable(): Promise { + const result = await gitCommandRunner(["--version"]) + return result.code === 0 +} + +export function validateWorktreeSpec(spec: string): void { + if (!/^(\.\.?\/|\/).+/.test(spec) || countParentSegments(spec) > 2) { + throw new Error("worktreePath must be a filesystem path (relative './...', '../...' or absolute '/...')") + } +} + +export async function createWorktree( + repoRoot: string, + _teamRunId: string, + _memberName: string, + worktreePath: string, + _config: TeamModeConfig, +): Promise { + validateWorktreeSpec(worktreePath) + + if (!(await isGitAvailable())) { + throw new GitUnavailableError() + } + + const absolutePath = path.isAbsolute(worktreePath) ? worktreePath : path.resolve(repoRoot, worktreePath) + const result = await gitCommandRunner(["-C", repoRoot, "worktree", "add", "--detach", absolutePath]) + + if (result.code !== 0) { + throw new Error(result.stderr.trim() || "git worktree add failed") + } + + return absolutePath +} diff --git a/src/features/team-mode/types.test.ts b/src/features/team-mode/types.test.ts new file mode 100644 index 000000000..042f220e5 --- /dev/null +++ b/src/features/team-mode/types.test.ts @@ -0,0 +1,96 @@ +import { describe, expect, test } from "bun:test" +import { + AGENT_ELIGIBILITY_REGISTRY, + CategoryMemberSchema, + MemberSchema, + SubagentMemberSchema, +} from "./types" + +describe("team-mode types", () => { + test("member category branch parses and narrows", () => { + // given + const member = { kind: "category", name: "m1", category: "deep", prompt: "impl X" } + + // when + const result = MemberSchema.safeParse(member) + + // then + expect(result.success).toBe(true) + if (result.success) { + expect(result.data).toMatchObject(member) + expect(result.data).toMatchObject({ kind: "category", category: "deep" }) + } + }) + + test("both kinds rejected", () => { + // given + const member = { + kind: "category", + name: "m1", + category: "deep", + subagent_type: "sisyphus", + prompt: "impl X", + } + + // when + const result = MemberSchema.safeParse(member) + + // then + expect(result.success).toBe(false) + }) + + test("category requires prompt", () => { + // given + const member = { kind: "category", name: "m1", category: "deep" } + + // when + const result = CategoryMemberSchema.safeParse(member) + + // then + expect(result.success).toBe(false) + }) + + test("eligibility registry shape", () => { + // given + const entries = Object.entries(AGENT_ELIGIBILITY_REGISTRY) + + // when + const verdictCounts = entries.reduce( + (counts, [, value]) => { + counts[value.verdict] += 1 + return counts + }, + { eligible: 0, conditional: 0, "hard-reject": 0 }, + ) + + // then + expect(entries).toHaveLength(11) + expect(verdictCounts).toEqual({ eligible: 3, conditional: 1, "hard-reject": 7 }) + expect(AGENT_ELIGIBILITY_REGISTRY.hephaestus.rejectionMessage).toBe( + "Agent 'hephaestus' lacks teammate permission. Either apply D-36 (add teammate: \"allow\" in tool-config-handler.ts) or use subagent_type: \"sisyphus\" instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.oracle.rejectionMessage).toBe( + "Agent 'oracle' is read-only (cannot write files). Team members must write to mailbox inbox files. Use delegate-task with subagent_type: 'oracle' for read-only analysis instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.librarian.rejectionMessage).toBe( + "Agent 'librarian' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for research queries instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.explore.rejectionMessage).toBe( + "Agent 'explore' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for codebase exploration instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY["multimodal-looker"].rejectionMessage).toBe( + "Agent 'multimodal-looker' has read-only tool access (only 'read' allowed). Cannot write to mailbox as team member.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.metis.rejectionMessage).toBe( + "Agent 'metis' is read-only (pre-planning consultant). Cannot write to mailbox as team member. Use delegate-task for pre-planning analysis instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.momus.rejectionMessage).toBe( + "Agent 'momus' is read-only (plan reviewer). Cannot write to mailbox as team member. Use delegate-task for plan review instead.", + ) + expect(AGENT_ELIGIBILITY_REGISTRY.prometheus.rejectionMessage).toBe( + "Agent 'prometheus' is plan-mode-only; can only write to .sisyphus/*.md (enforced by prometheusMdOnly hook). Cannot write to team mailbox. Use category: 'plan' instead.", + ) + expect(CategoryMemberSchema).toBeDefined() + expect(SubagentMemberSchema).toBeDefined() + }) +}) diff --git a/src/features/team-mode/types.ts b/src/features/team-mode/types.ts new file mode 100644 index 000000000..2b2da3f2a --- /dev/null +++ b/src/features/team-mode/types.ts @@ -0,0 +1,190 @@ +import { z } from "zod" + +export const MESSAGE_KINDS = [ + "message", + "shutdown_request", + "shutdown_approved", + "shutdown_rejected", + "announcement", +] as const + +export const MEMBER_KINDS = ["category", "subagent_type"] as const + +export const TASK_STATUSES = ["pending", "claimed", "in_progress", "completed", "deleted"] as const + +export const RUNTIME_STATUSES = [ + "creating", + "active", + "shutdown_requested", + "deleting", + "deleted", + "failed", + "orphaned", +] as const + +const MemberBaseSchema = z.object({ + name: z.string().min(1).regex(/^[a-z0-9-]+$/), + cwd: z.string().optional(), + worktreePath: z.string().optional(), + subscriptions: z.array(z.string()).optional(), + backendType: z.enum(["in-process", "tmux"]).default("in-process"), + color: z.string().optional(), + isActive: z.boolean().default(true), +}).strict() + +export const CategoryMemberSchema = MemberBaseSchema.extend({ + kind: z.literal("category"), + category: z.string().min(1), + prompt: z.string().min(1), +}) + +export const SubagentMemberSchema = MemberBaseSchema.extend({ + kind: z.literal("subagent_type"), + subagent_type: z.string().min(1), + prompt: z.string().optional(), +}) + +export const MemberSchema = z.discriminatedUnion("kind", [CategoryMemberSchema, SubagentMemberSchema]) + +const TeamReferenceSchema = z.object({ + path: z.string(), + description: z.string().optional(), +}).strict() + +export const TeamSpecSchema = z.object({ + version: z.literal(1), + name: z.string().min(1).regex(/^[a-z0-9-]+$/), + description: z.string().optional(), + createdAt: z.number().int().positive(), + leadAgentId: z.string(), + teamAllowedPaths: z.array(z.string()).optional(), + sessionPermission: z.string().optional(), + members: z.array(MemberSchema).min(1).max(8), +}) + +export const MessageSchema = z.object({ + version: z.literal(1), + messageId: z.string().uuid(), + from: z.string(), + to: z.string(), + kind: z.enum(MESSAGE_KINDS), + body: z.string().max(32 * 1024), + summary: z.string().optional(), + references: z.array(TeamReferenceSchema).optional(), + timestamp: z.number().int().positive(), + correlationId: z.string().uuid().optional(), + color: z.string().optional(), +}) + +export const TaskSchema = z.object({ + version: z.literal(1), + id: z.string(), + subject: z.string(), + description: z.string(), + activeForm: z.string().optional(), + status: z.enum(TASK_STATUSES), + owner: z.string().optional(), + blocks: z.array(z.string()).default([]), + blockedBy: z.array(z.string()).default([]), + metadata: z.record(z.string(), z.unknown()).optional(), + createdAt: z.number().int().positive(), + updatedAt: z.number().int().positive(), + claimedAt: z.number().int().positive().optional(), +}) + +const RuntimeStateMemberSchema = z.object({ + name: z.string(), + sessionId: z.string().optional(), + tmuxPaneId: z.string().optional(), + agentType: z.enum(["leader", "general-purpose"]), + status: z.enum(["pending", "running", "idle", "errored", "completed", "shutdown_approved"]), + color: z.string().optional(), + worktreePath: z.string().optional(), + lastInjectedTurnMarker: z.string().optional(), + pendingInjectedMessageIds: z.array(z.string()).default([]), +}).strict() + +const RuntimeBoundsSchema = z.object({ + maxMembers: z.number().int().default(8), + maxParallelMembers: z.number().int().default(4), + maxMessagesPerRun: z.number().int().default(10000), + maxWallClockMinutes: z.number().int().default(120), + maxMemberTurns: z.number().int().default(500), +}).strict() + +const ShutdownRequestSchema = z.object({ + memberId: z.string(), + requestedAt: z.number().int().positive(), + approvedAt: z.number().int().positive().optional(), + rejectedReason: z.string().optional(), +}).strict() + +export const RuntimeStateSchema = z.object({ + version: z.literal(1), + teamRunId: z.string().uuid(), + teamName: z.string(), + specSource: z.enum(["project", "user"]), + createdAt: z.number().int().positive(), + status: z.enum(RUNTIME_STATUSES), + leadSessionId: z.string().optional(), + members: z.array(RuntimeStateMemberSchema), + shutdownRequests: z.array(ShutdownRequestSchema).default([]), + bounds: RuntimeBoundsSchema, +}) + +export const AGENT_ELIGIBILITY_REGISTRY: Readonly> = { + sisyphus: { verdict: "eligible" }, + hephaestus: { + verdict: "conditional", + rejectionMessage: + "Agent 'hephaestus' lacks teammate permission. Either apply D-36 (add teammate: \"allow\" in tool-config-handler.ts) or use subagent_type: \"sisyphus\" instead.", + }, + oracle: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'oracle' is read-only (cannot write files). Team members must write to mailbox inbox files. Use delegate-task with subagent_type: 'oracle' for read-only analysis instead.", + }, + librarian: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'librarian' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for research queries instead.", + }, + explore: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'explore' is read-only (write/edit denied). Cannot write to mailbox as team member. Use delegate-task for codebase exploration instead.", + }, + "multimodal-looker": { + verdict: "hard-reject", + rejectionMessage: + "Agent 'multimodal-looker' has read-only tool access (only 'read' allowed). Cannot write to mailbox as team member.", + }, + metis: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'metis' is read-only (pre-planning consultant). Cannot write to mailbox as team member. Use delegate-task for pre-planning analysis instead.", + }, + momus: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'momus' is read-only (plan reviewer). Cannot write to mailbox as team member. Use delegate-task for plan review instead.", + }, + atlas: { verdict: "eligible" }, + prometheus: { + verdict: "hard-reject", + rejectionMessage: + "Agent 'prometheus' is plan-mode-only; can only write to .sisyphus/*.md (enforced by prometheusMdOnly hook). Cannot write to team mailbox. Use category: 'plan' instead.", + }, + "sisyphus-junior": { verdict: "eligible" }, +} as const + +export type TeamSpec = z.infer +export type Member = z.infer +export type CategoryMember = z.infer +export type SubagentMember = z.infer +export type Message = z.infer +export type Task = z.infer +export type RuntimeState = z.infer diff --git a/src/features/tmux-subagent/cleanup.ts b/src/features/tmux-subagent/cleanup.ts deleted file mode 100644 index 414ad00bc..000000000 --- a/src/features/tmux-subagent/cleanup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { TmuxConfig } from "../../config/schema" -import { log } from "../../shared" -import type { TrackedSession } from "./types" -import { queryWindowState } from "./pane-state-querier" -import { executeAction } from "./action-executor" - -export async function cleanupTmuxSessions(params: { - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - stopPolling: () => void -}): Promise { - params.stopPolling() - - if (params.sessions.size === 0) { - log("[tmux-session-manager] cleanup complete") - return - } - - log("[tmux-session-manager] closing all panes", { count: params.sessions.size }) - const state = params.sourcePaneId ? await queryWindowState(params.sourcePaneId) : null - - if (state) { - const closePromises = Array.from(params.sessions.values()).map((tracked) => - executeAction( - { type: "close", paneId: tracked.paneId, sessionId: tracked.sessionId }, - { config: params.tmuxConfig, serverUrl: params.serverUrl, windowState: state }, - ).catch((error) => - log("[tmux-session-manager] cleanup error for pane", { - paneId: tracked.paneId, - error: String(error), - }), - ), - ) - - await Promise.all(closePromises) - } - - params.sessions.clear() - log("[tmux-session-manager] cleanup complete") -} diff --git a/src/features/tmux-subagent/event-handlers.ts b/src/features/tmux-subagent/event-handlers.ts index 0991d10e2..2916c7439 100644 --- a/src/features/tmux-subagent/event-handlers.ts +++ b/src/features/tmux-subagent/event-handlers.ts @@ -1,6 +1,2 @@ export { coerceSessionCreatedEvent } from "./session-created-event" export type { SessionCreatedEvent } from "./session-created-event" -export { handleSessionCreated } from "./session-created-handler" -export type { SessionCreatedHandlerDeps } from "./session-created-handler" -export { handleSessionDeleted } from "./session-deleted-handler" -export type { SessionDeletedHandlerDeps } from "./session-deleted-handler" diff --git a/src/features/tmux-subagent/index.ts b/src/features/tmux-subagent/index.ts index e900555fb..cba66fa6b 100644 --- a/src/features/tmux-subagent/index.ts +++ b/src/features/tmux-subagent/index.ts @@ -1,10 +1,7 @@ export * from "./manager" export * from "./event-handlers" export * from "./polling" -export * from "./cleanup" export * from "./session-created-event" -export * from "./session-created-handler" -export * from "./session-deleted-handler" export * from "./polling-constants" export * from "./session-status-parser" export * from "./session-message-count" diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 8c47097f4..e63f4bf4d 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -57,6 +57,8 @@ const mockSpawnTmuxSession = mock<( success: true, paneId: '%isolated-session', })) +const mockKillTmuxSessionIfExists = mock<(sessionName: string) => Promise>(async () => true) +const mockSweepStaleOmoAgentSessions = mock<() => Promise>(async () => 0) const mockIsInsideTmux = mock<() => boolean>(() => true) const mockGetCurrentPaneId = mock<() => string | undefined>(() => '%0') @@ -99,6 +101,9 @@ mock.module('../../shared/tmux', () => { SESSION_READY_TIMEOUT_MS: 500, spawnTmuxWindow: mockSpawnTmuxWindow, spawnTmuxSession: mockSpawnTmuxSession, + killTmuxSessionIfExists: mockKillTmuxSessionIfExists, + getIsolatedSessionName: (pid: number = 12345) => `omo-agents-${pid}`, + sweepStaleOmoAgentSessions: mockSweepStaleOmoAgentSessions, } }) @@ -1056,6 +1061,27 @@ describe('TmuxSessionManager', () => { logSpy.mockRestore() }) }) + + test('#given session.status never reports session ready #when onSessionCreated runs #then pane is tracked immediately without blocking', async () => { + // given + mockIsInsideTmux.mockReturnValue(true) + mockQueryWindowState.mockImplementation(async () => createWindowState()) + + const { TmuxSessionManager } = await import('./manager') + const ctx = createMockContext({ sessionStatusResult: { data: {} } }) + const config = createTmuxConfig({ enabled: true }) + const manager = new TmuxSessionManager(ctx, config, mockTmuxDeps) + const event = createSessionCreatedEvent('ses_fast_track', 'ses_parent', 'Fast Track') + + // when + const start = Date.now() + await manager.onSessionCreated(event) + const elapsed = Date.now() - start + + // then + expect(elapsed < 500).toBe(true) + expect(getTrackedSessions(manager).has('ses_fast_track')).toBe(true) + }) }) describe('onSessionDeleted', () => { @@ -1831,6 +1857,141 @@ describe('TmuxSessionManager', () => { // then expect(mockExecuteAction).toHaveBeenCalledTimes(2) }) + + test('#given tmux isolation is "session" #when cleanup runs #then killTmuxSessionIfExists is invoked for the per-pid isolated session', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) + expect(mockKillTmuxSessionIfExists.mock.calls[0]?.[0]).toMatch(/^omo-agents-\d+$/) + }) + + test('#given two manager instances #when both cleanup #then each kills its own isolated session name, not a shared one', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const managerA = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + const managerB = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await managerA.cleanup() + await managerB.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(2) + const firstTarget = mockKillTmuxSessionIfExists.mock.calls[0]?.[0] + const secondTarget = mockKillTmuxSessionIfExists.mock.calls[1]?.[0] + expect(firstTarget).toMatch(/^omo-agents-\d+$/) + expect(secondTarget).toMatch(/^omo-agents-\d+$/) + }) + + test('#given tmux isolation is "inline" #when cleanup runs #then killTmuxSessionIfExists is NOT invoked', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'inline', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) + }) + + test('#given tmux isolation is "window" #when cleanup runs #then killTmuxSessionIfExists is NOT invoked', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'window', + }), mockTmuxDeps) + + // when + await manager.cleanup() + + // then + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(0) + }) + + test('#given sweepStaleOmoAgentSessions throws on first onSessionCreated #when second onSessionCreated fires #then sweep is retried instead of skipped forever', async () => { + // given + mockSweepStaleOmoAgentSessions.mockClear() + mockSweepStaleOmoAgentSessions.mockImplementationOnce(async () => { + throw new Error('simulated sweep failure') + }) + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.onSessionCreated(createSessionCreatedEvent('ses_first', 'ses_parent', 'First')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_second', 'ses_parent', 'Second')) + + // then + expect(mockSweepStaleOmoAgentSessions).toHaveBeenCalledTimes(2) + }) + + test('#given sweepStaleOmoAgentSessions succeeds #when additional onSessionCreated events fire in same process #then sweep runs exactly once', async () => { + // given + mockSweepStaleOmoAgentSessions.mockClear() + mockSweepStaleOmoAgentSessions.mockImplementation(async () => 0) + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + await manager.onSessionCreated(createSessionCreatedEvent('ses_a', 'ses_parent', 'A')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_b', 'ses_parent', 'B')) + await manager.onSessionCreated(createSessionCreatedEvent('ses_c', 'ses_parent', 'C')) + + // then + expect(mockSweepStaleOmoAgentSessions).toHaveBeenCalledTimes(1) + }) + + test('#given killTmuxSessionIfExists throws #when cleanup runs #then cleanup still completes without throwing', async () => { + // given + mockKillTmuxSessionIfExists.mockClear() + mockKillTmuxSessionIfExists.mockImplementationOnce(async () => { + throw new Error('simulated teardown failure') + }) + const { TmuxSessionManager } = await import('./manager') + const manager = new TmuxSessionManager(createMockContext(), createTmuxConfig({ + enabled: true, + isolation: 'session', + }), mockTmuxDeps) + + // when + const cleanupPromise = manager.cleanup() + + // then + await expect(cleanupPromise).resolves.toBeUndefined() + expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) + }) }) }) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index a31f668bf..3340fb55d 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -10,6 +10,9 @@ import { SESSION_READY_TIMEOUT_MS, spawnTmuxWindow, spawnTmuxSession, + killTmuxSessionIfExists, + getIsolatedSessionName, + sweepStaleOmoAgentSessions, } from "../../shared/tmux" import { queryWindowState } from "./pane-state-querier" import { decideSpawnActions, decideCloseAction, type SessionMapping } from "./decision-engine" @@ -63,6 +66,8 @@ export class TmuxSessionManager { private isolatedContainerPaneId: string | undefined private isolatedWindowPaneId: string | undefined private isolatedContainerNullStateCount = 0 + private staleSweepCompleted = false + private staleSweepInProgress = false constructor(ctx: PluginInput, tmuxConfig: TmuxConfig, deps: TmuxUtilDeps = defaultTmuxDeps) { this.client = ctx.client this.tmuxConfig = tmuxConfig @@ -89,7 +94,8 @@ export class TmuxSessionManager { this.pollingManager = new TmuxPollingManager( this.client, this.sessions, - this.closeSessionById.bind(this) + this.closeSessionById.bind(this), + this.retryPendingCloses.bind(this) ) log("[tmux-session-manager] initialized", { configEnabled: this.tmuxConfig.enabled, @@ -511,7 +517,6 @@ export class TmuxSessionManager { if (deferred.retryIsolatedContainer) { const isolatedPaneId = await this.spawnInIsolatedContainer(sessionId, deferred.title) if (isolatedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) this.sessions.set( sessionId, createTrackedSession({ @@ -525,8 +530,8 @@ export class TmuxSessionManager { log("[tmux-session-manager] deferred session attached in isolated window", { sessionId, paneId: isolatedPaneId, - sessionReady, }) + this.logSessionReadinessInBackground(sessionId) return } } @@ -585,14 +590,6 @@ export class TmuxSessionManager { return } - const sessionReady = await this.waitForSessionReady(sessionId) - if (!sessionReady) { - log("[tmux-session-manager] deferred session not ready after timeout", { - sessionId, - paneId: result.spawnedPaneId, - }) - } - this.sessions.set( sessionId, createTrackedSession({ @@ -606,18 +603,27 @@ export class TmuxSessionManager { log("[tmux-session-manager] deferred session attached", { sessionId, paneId: result.spawnedPaneId, - sessionReady, + }) + this.logSessionReadinessInBackground(sessionId) + } + + private logSessionReadinessInBackground(sessionId: string): void { + void this.waitForSessionReady(sessionId).catch((error) => { + log("[tmux-session-manager] background readiness probe failed", { + sessionId, + error: String(error), + }) }) } private async waitForSessionReady(sessionId: string): Promise { const startTime = Date.now() - + while (Date.now() - startTime < SESSION_READY_TIMEOUT_MS) { try { const statusResult = await this.client.session.status({ path: undefined }) const allStatuses = normalizeSDKResponse(statusResult, {} as Record) - + if (allStatuses[sessionId]) { log("[tmux-session-manager] session ready", { sessionId, @@ -629,10 +635,10 @@ export class TmuxSessionManager { } catch (err) { log("[tmux-session-manager] session status check error", { error: String(err) }) } - + await new Promise((resolve) => setTimeout(resolve, SESSION_READY_POLL_INTERVAL_MS)) } - + log("[tmux-session-manager] session ready timeout", { sessionId, timeoutMs: SESSION_READY_TIMEOUT_MS, @@ -665,6 +671,7 @@ export class TmuxSessionManager { return } + await this.sweepStaleIsolatedSessionsOnce() await this.retryPendingCloses() if ( @@ -682,7 +689,6 @@ export class TmuxSessionManager { try { const isolatedPaneId = await this.spawnInIsolatedContainer(sessionId, title) if (isolatedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) this.sessions.set( sessionId, createTrackedSession({ sessionId, paneId: isolatedPaneId, description: title }), @@ -691,8 +697,8 @@ export class TmuxSessionManager { log("[tmux-session-manager] first subagent spawned in isolated window", { sessionId, paneId: isolatedPaneId, - sessionReady, }) + this.logSessionReadinessInBackground(sessionId) return } @@ -773,15 +779,6 @@ export class TmuxSessionManager { } if (result.success && result.spawnedPaneId) { - const sessionReady = await this.waitForSessionReady(sessionId) - - if (!sessionReady) { - log("[tmux-session-manager] session not ready after timeout, tracking anyway", { - sessionId, - paneId: result.spawnedPaneId, - }) - } - this.sessions.set( sessionId, createTrackedSession({ @@ -793,9 +790,9 @@ export class TmuxSessionManager { log("[tmux-session-manager] pane spawned and tracked", { sessionId, paneId: result.spawnedPaneId, - sessionReady, }) this.pollingManager.startPolling() + this.logSessionReadinessInBackground(sessionId) } else { log("[tmux-session-manager] spawn failed", { success: result.success, @@ -964,6 +961,49 @@ export class TmuxSessionManager { this.isolatedContainerPaneId = undefined this.isolatedWindowPaneId = undefined + if (this.tmuxConfig.isolation === "session") { + const isolatedSessionName = getIsolatedSessionName() + try { + const killed = await killTmuxSessionIfExists(isolatedSessionName) + log("[tmux-session-manager] isolated session teardown", { + session: isolatedSessionName, + killed, + }) + } catch (error) { + log("[tmux-session-manager] isolated session teardown failed", { + session: isolatedSessionName, + error: String(error), + }) + } + } + + this.staleSweepCompleted = false + this.staleSweepInProgress = false + log("[tmux-session-manager] cleanup complete") } + + private async sweepStaleIsolatedSessionsOnce(): Promise { + if (this.staleSweepCompleted) return + if (this.staleSweepInProgress) return + if (this.tmuxConfig.isolation !== "session") { + this.staleSweepCompleted = true + return + } + + this.staleSweepInProgress = true + try { + const killed = await sweepStaleOmoAgentSessions() + if (killed > 0) { + log("[tmux-session-manager] stale isolated sessions swept", { killed }) + } + this.staleSweepCompleted = true + } catch (error) { + log("[tmux-session-manager] stale sweep failed", { + error: String(error), + }) + } finally { + this.staleSweepInProgress = false + } + } } diff --git a/src/features/tmux-subagent/polling-manager.ts b/src/features/tmux-subagent/polling-manager.ts index d7a972d40..1a74be801 100644 --- a/src/features/tmux-subagent/polling-manager.ts +++ b/src/features/tmux-subagent/polling-manager.ts @@ -16,7 +16,8 @@ export class TmuxPollingManager { constructor( private client: OpencodeClient, private sessions: Map, - private closeSessionById: (sessionId: string) => Promise + private closeSessionById: (sessionId: string) => Promise, + private retryPendingCloses?: () => Promise ) {} handleEvent(event: { type: string; properties?: Record }): void { @@ -134,6 +135,14 @@ export class TmuxPollingManager { log("[tmux-session-manager] closing session due to poll", { sessionId }) await this.closeSessionById(sessionId) } + + if (this.retryPendingCloses) { + try { + await this.retryPendingCloses() + } catch (err) { + log("[tmux-session-manager] retry pending closes failed", { error: String(err) }) + } + } } catch (err) { log("[tmux-session-manager] poll error", { error: String(err) }) } finally { diff --git a/src/features/tmux-subagent/session-created-handler.ts b/src/features/tmux-subagent/session-created-handler.ts deleted file mode 100644 index 6dd1f21eb..000000000 --- a/src/features/tmux-subagent/session-created-handler.ts +++ /dev/null @@ -1,175 +0,0 @@ -import type { PluginInput } from "@opencode-ai/plugin" -import type { TmuxConfig } from "../../config/schema" -import type { CapacityConfig, TrackedSession } from "./types" -import { log } from "../../shared" -import { queryWindowState } from "./pane-state-querier" -import { decideSpawnActions, type SessionMapping } from "./decision-engine" -import { executeActions } from "./action-executor" -import type { SessionCreatedEvent } from "./session-created-event" -import { createTrackedSession } from "./tracked-session-state" - -type OpencodeClient = PluginInput["client"] - -export interface SessionCreatedHandlerDeps { - client: OpencodeClient - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - pendingSessions: Set - isInsideTmux: () => boolean - isEnabled: () => boolean - getCapacityConfig: () => CapacityConfig - getSessionMappings: () => SessionMapping[] - waitForSessionReady: (sessionId: string) => Promise - startPolling: () => void -} - -export async function handleSessionCreated( - deps: SessionCreatedHandlerDeps, - event: SessionCreatedEvent, -): Promise { - const enabled = deps.isEnabled() - log("[tmux-session-manager] onSessionCreated called", { - enabled, - tmuxConfigEnabled: deps.tmuxConfig.enabled, - isInsideTmux: deps.isInsideTmux(), - eventType: event.type, - infoId: event.properties?.info?.id, - infoParentID: event.properties?.info?.parentID, - }) - - if (!enabled) return - if (event.type !== "session.created") return - - const info = event.properties?.info - if (!info?.id || !info?.parentID) return - - const sessionId = info.id - const title = info.title ?? "Subagent" - - if (deps.sessions.has(sessionId) || deps.pendingSessions.has(sessionId)) { - log("[tmux-session-manager] session already tracked or pending", { sessionId }) - return - } - - if (!deps.sourcePaneId) { - log("[tmux-session-manager] no source pane id") - return - } - - deps.pendingSessions.add(sessionId) - - try { - const state = await queryWindowState(deps.sourcePaneId) - if (!state) { - log("[tmux-session-manager] failed to query window state") - return - } - - log("[tmux-session-manager] window state queried", { - windowWidth: state.windowWidth, - mainPane: state.mainPane?.paneId, - agentPaneCount: state.agentPanes.length, - agentPanes: state.agentPanes.map((p) => p.paneId), - }) - - const decision = decideSpawnActions( - state, - sessionId, - title, - deps.getCapacityConfig(), - deps.getSessionMappings(), - ) - - log("[tmux-session-manager] spawn decision", { - canSpawn: decision.canSpawn, - reason: decision.reason, - actionCount: decision.actions.length, - actions: decision.actions.map((a) => { - if (a.type === "close") return { type: "close", paneId: a.paneId } - if (a.type === "replace") { - return { type: "replace", paneId: a.paneId, newSessionId: a.newSessionId } - } - return { type: "spawn", sessionId: a.sessionId } - }), - }) - - if (!decision.canSpawn) { - log("[tmux-session-manager] cannot spawn", { reason: decision.reason }) - return - } - - const result = await executeActions(decision.actions, { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }) - - for (const { action, result: actionResult } of result.results) { - if (action.type === "close" && actionResult.success) { - deps.sessions.delete(action.sessionId) - log("[tmux-session-manager] removed closed session from cache", { - sessionId: action.sessionId, - }) - } - if (action.type === "replace" && actionResult.success) { - deps.sessions.delete(action.oldSessionId) - log("[tmux-session-manager] removed replaced session from cache", { - oldSessionId: action.oldSessionId, - newSessionId: action.newSessionId, - }) - } - } - - if (!result.success || !result.spawnedPaneId) { - log("[tmux-session-manager] spawn failed", { - success: result.success, - results: result.results.map((r) => ({ - type: r.action.type, - success: r.result.success, - error: r.result.error, - })), - }) - return - } - - const sessionReady = await deps.waitForSessionReady(sessionId) - if (!sessionReady) { - log("[tmux-session-manager] session not ready after timeout, closing spawned pane", { - sessionId, - paneId: result.spawnedPaneId, - }) - - await executeActions( - [{ type: "close", paneId: result.spawnedPaneId, sessionId }], - { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }, - ) - - return - } - - deps.sessions.set( - sessionId, - createTrackedSession({ - sessionId, - paneId: result.spawnedPaneId, - description: title, - }), - ) - - log("[tmux-session-manager] pane spawned and tracked", { - sessionId, - paneId: result.spawnedPaneId, - sessionReady, - }) - - deps.startPolling() - } finally { - deps.pendingSessions.delete(sessionId) - } -} diff --git a/src/features/tmux-subagent/session-deleted-handler.ts b/src/features/tmux-subagent/session-deleted-handler.ts deleted file mode 100644 index f832cf481..000000000 --- a/src/features/tmux-subagent/session-deleted-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { TmuxConfig } from "../../config/schema" -import type { TrackedSession } from "./types" -import { log } from "../../shared" -import { queryWindowState } from "./pane-state-querier" -import { decideCloseAction, type SessionMapping } from "./decision-engine" -import { executeAction } from "./action-executor" - -export interface SessionDeletedHandlerDeps { - tmuxConfig: TmuxConfig - serverUrl: string - sourcePaneId: string | undefined - sessions: Map - isEnabled: () => boolean - getSessionMappings: () => SessionMapping[] - stopPolling: () => void -} - -export async function handleSessionDeleted( - deps: SessionDeletedHandlerDeps, - event: { sessionID: string }, -): Promise { - if (!deps.isEnabled()) return - if (!deps.sourcePaneId) return - - const tracked = deps.sessions.get(event.sessionID) - if (!tracked) return - - log("[tmux-session-manager] onSessionDeleted", { sessionId: event.sessionID }) - - const state = await queryWindowState(deps.sourcePaneId) - if (!state) { - deps.sessions.delete(event.sessionID) - return - } - - const closeAction = decideCloseAction(state, event.sessionID, deps.getSessionMappings()) - if (closeAction) { - await executeAction(closeAction, { - config: deps.tmuxConfig, - serverUrl: deps.serverUrl, - windowState: state, - }) - } - - deps.sessions.delete(event.sessionID) - - if (deps.sessions.size === 0) { - deps.stopPolling() - } -} diff --git a/src/features/tool-metadata-store/index.ts b/src/features/tool-metadata-store/index.ts index f9c4e28ad..cc89a9f72 100644 --- a/src/features/tool-metadata-store/index.ts +++ b/src/features/tool-metadata-store/index.ts @@ -5,3 +5,10 @@ export { storeToolMetadata, } from "./store" export type { PendingToolMetadata } from "./store" +export { resolveToolCallID } from "./resolve-tool-call-id" +export type { ToolCallIDCarrier } from "./resolve-tool-call-id" +export { buildTaskMetadataBlock, extractTaskLink, parseTaskMetadataBlock } from "./task-metadata-contract" +export type { TaskLink } from "./task-metadata-contract" +export { publishToolMetadata } from "./publish-tool-metadata" +export { recoverToolMetadata } from "./recover-tool-metadata" +export type { ToolMetadataPublisherContext } from "./publish-tool-metadata" diff --git a/src/features/tool-metadata-store/integration.test.ts b/src/features/tool-metadata-store/integration.test.ts new file mode 100644 index 000000000..2604a5edf --- /dev/null +++ b/src/features/tool-metadata-store/integration.test.ts @@ -0,0 +1,96 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { clearPendingStore, getPendingStoreSize } from "./store" +import { publishToolMetadata } from "./publish-tool-metadata" +import { recoverToolMetadata } from "./recover-tool-metadata" + +describe("tool-metadata-store integration", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given stored metadata #when publishing then recovering #then the round trip preserves the payload", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_123" }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_123" }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given call id casing mismatch #when publishing and recovering #then canonical resolution still matches", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + await publishToolMetadata({ sessionID: "ses_parent", callId: "call_case" }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_case" }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given blank call id #when publishing #then nothing is stored", async () => { + // given + const payload = { title: "Task" } + + // when + const result = await publishToolMetadata({ sessionID: "ses_parent", callID: " " }, payload) + const recovered = recoverToolMetadata("ses_parent", { callID: "call_blank" }) + + // then + expect(result).toEqual({ stored: false }) + expect(recovered).toBeUndefined() + expect(getPendingStoreSize()).toBe(0) + }) + + test("#given missing call id #when publishing #then nothing is stored", async () => { + // given + const payload = { title: "Task" } + + // when + const result = await publishToolMetadata({ sessionID: "ses_parent" }, payload) + + // then + expect(result).toEqual({ stored: false }) + expect(getPendingStoreSize()).toBe(0) + }) + + test("#given same session with different call ids #when publishing twice #then each entry stays isolated", async () => { + // given + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_a" }, { title: "A" }) + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_b" }, { title: "B" }) + + // when + const recoveredA = recoverToolMetadata("ses_parent", { callID: "call_a" }) + const recoveredB = recoverToolMetadata("ses_parent", { callID: "call_b" }) + + // then + expect(recoveredA).toEqual({ title: "A" }) + expect(recoveredB).toEqual({ title: "B" }) + }) + + test("#given stale metadata #when a fresh entry is stored after the timeout #then stale entries are cleaned up", async () => { + // given + const originalDateNow = Date.now + let now = 0 + Date.now = () => now + + try { + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_old" }, { title: "Old" }) + now = 15 * 60 * 1000 + 1 + + // when + await publishToolMetadata({ sessionID: "ses_parent", callID: "call_new" }, { title: "New" }) + + // then + expect(recoverToolMetadata("ses_parent", { callID: "call_old" })).toBeUndefined() + expect(recoverToolMetadata("ses_parent", { callID: "call_new" })).toEqual({ title: "New" }) + } finally { + Date.now = originalDateNow + } + }) +}) diff --git a/src/features/tool-metadata-store/publish-tool-metadata.test.ts b/src/features/tool-metadata-store/publish-tool-metadata.test.ts new file mode 100644 index 000000000..704fe2392 --- /dev/null +++ b/src/features/tool-metadata-store/publish-tool-metadata.test.ts @@ -0,0 +1,76 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { clearPendingStore, consumeToolMetadata } from "./store" +import { publishToolMetadata } from "./publish-tool-metadata" + +describe("publishToolMetadata", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given metadata context and call id #when publishing #then it awaits metadata and stores the payload", async () => { + // given + const calls: string[] = [] + let metadataFinished = false + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + callID: "call_123", + metadata: async input => { + calls.push(input.title ?? "") + await new Promise(resolve => setTimeout(resolve, 1)) + metadataFinished = true + }, + }, + payload + ) + + // then + expect(result).toEqual({ stored: true }) + expect(metadataFinished).toBe(true) + expect(calls).toEqual(["Task"]) + expect(consumeToolMetadata("ses_parent", "call_123")).toEqual(payload) + }) + + test("#given legacy call id variant #when publishing #then it stores with the canonical resolver", async () => { + // given + const payload = { title: "Task", metadata: { sessionId: "ses_child" } } + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + callId: " call_legacy ", + }, + payload + ) + + // then + expect(result).toEqual({ stored: true }) + expect(consumeToolMetadata("ses_parent", "call_legacy")).toEqual(payload) + }) + + test("#given missing call id #when publishing #then it still emits metadata but skips storing", async () => { + // given + let metadataCalls = 0 + + // when + const result = await publishToolMetadata( + { + sessionID: "ses_parent", + metadata: () => { + metadataCalls += 1 + }, + }, + { title: "Task" } + ) + + // then + expect(result).toEqual({ stored: false }) + expect(metadataCalls).toBe(1) + expect(consumeToolMetadata("ses_parent", "call_missing")).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/publish-tool-metadata.ts b/src/features/tool-metadata-store/publish-tool-metadata.ts new file mode 100644 index 000000000..84e69155e --- /dev/null +++ b/src/features/tool-metadata-store/publish-tool-metadata.ts @@ -0,0 +1,28 @@ +import { log } from "../../shared/logger" +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" +import { storeToolMetadata, type PendingToolMetadata } from "./store" + +export interface ToolMetadataPublisherContext extends ToolCallIDCarrier { + sessionID: string + metadata?: (input: PendingToolMetadata) => void | Promise +} + +export async function publishToolMetadata( + ctx: ToolMetadataPublisherContext, + payload: PendingToolMetadata +): Promise<{ stored: boolean }> { + await ctx.metadata?.(payload) + + const callID = resolveToolCallID(ctx) + if (!callID) { + log("[tool-metadata-store] Skipping metadata store publish because tool call ID is unavailable", { + sessionID: ctx.sessionID, + hasTitle: typeof payload.title === "string", + hasMetadata: payload.metadata !== undefined, + }) + return { stored: false } + } + + storeToolMetadata(ctx.sessionID, callID, payload) + return { stored: true } +} diff --git a/src/features/tool-metadata-store/recover-tool-metadata.test.ts b/src/features/tool-metadata-store/recover-tool-metadata.test.ts new file mode 100644 index 000000000..e97e87eea --- /dev/null +++ b/src/features/tool-metadata-store/recover-tool-metadata.test.ts @@ -0,0 +1,47 @@ +import { beforeEach, describe, expect, test } from "bun:test" + +import { recoverToolMetadata } from "./recover-tool-metadata" +import { clearPendingStore, storeToolMetadata } from "./store" + +describe("recoverToolMetadata", () => { + beforeEach(() => { + clearPendingStore() + }) + + test("#given stored metadata and call id variant #when recovering #then it finds the stored payload", () => { + // given + const payload = { title: "Recovered", metadata: { sessionId: "ses_child" } } + storeToolMetadata("ses_parent", "call_123", payload) + + // when + const recovered = recoverToolMetadata("ses_parent", { callId: " call_123 " }) + + // then + expect(recovered).toEqual(payload) + }) + + test("#given direct string call id #when recovering #then it consumes the stored payload", () => { + // given + const payload = { title: "Recovered" } + storeToolMetadata("ses_parent", "call_456", payload) + + // when + const recovered = recoverToolMetadata("ses_parent", "call_456") + + // then + expect(recovered).toEqual(payload) + }) + + test("#given missing or blank call id #when recovering #then it returns undefined", () => { + // given + storeToolMetadata("ses_parent", "call_789", { title: "Recovered" }) + + // when + const missing = recoverToolMetadata("ses_parent", undefined) + const blank = recoverToolMetadata("ses_parent", { callID: " " }) + + // then + expect(missing).toBeUndefined() + expect(blank).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/recover-tool-metadata.ts b/src/features/tool-metadata-store/recover-tool-metadata.ts new file mode 100644 index 000000000..17a2278e6 --- /dev/null +++ b/src/features/tool-metadata-store/recover-tool-metadata.ts @@ -0,0 +1,18 @@ +import { consumeToolMetadata, type PendingToolMetadata } from "./store" +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" + +export function recoverToolMetadata( + sessionID: string, + source: ToolCallIDCarrier | string | undefined +): PendingToolMetadata | undefined { + if (typeof source === "string") { + return consumeToolMetadata(sessionID, source) + } + + const callID = source ? resolveToolCallID(source) : undefined + if (!callID) { + return undefined + } + + return consumeToolMetadata(sessionID, callID) +} diff --git a/src/features/tool-metadata-store/resolve-tool-call-id.test.ts b/src/features/tool-metadata-store/resolve-tool-call-id.test.ts new file mode 100644 index 000000000..2ad63a516 --- /dev/null +++ b/src/features/tool-metadata-store/resolve-tool-call-id.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, test } from "bun:test" + +import { resolveToolCallID, type ToolCallIDCarrier } from "./resolve-tool-call-id" + +describe("resolveToolCallID", () => { + function makeCtx(overrides: Partial = {}): ToolCallIDCarrier { + return { + ...overrides, + } + } + + test("#given callID is set #when resolving #then it returns callID", () => { + // given + const ctx = makeCtx({ callID: "call_abc" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_abc") + }) + + test("#given only callId is set #when resolving #then it returns callId", () => { + // given + const ctx = makeCtx({ callId: "call_def" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_def") + }) + + test("#given only call_id is set #when resolving #then it returns call_id", () => { + // given + const ctx = makeCtx({ call_id: "call_ghi" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_ghi") + }) + + test("#given surrounding whitespace #when resolving #then it trims the value", () => { + // given + const ctx = makeCtx({ callID: " call_trimmed " }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBe("call_trimmed") + }) + + test("#given blank callID #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx({ callID: "" }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) + + test("#given whitespace callID #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx({ callID: " " }) + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) + + test("#given no call id variants #when resolving #then it returns undefined", () => { + // given + const ctx = makeCtx() + + // when + const result = resolveToolCallID(ctx) + + // then + expect(result).toBeUndefined() + }) +}) diff --git a/src/features/tool-metadata-store/resolve-tool-call-id.ts b/src/features/tool-metadata-store/resolve-tool-call-id.ts new file mode 100644 index 000000000..d5879ae5f --- /dev/null +++ b/src/features/tool-metadata-store/resolve-tool-call-id.ts @@ -0,0 +1,26 @@ +import { log } from "../../shared/logger" + +export interface ToolCallIDCarrier { + callID?: string + callId?: string + call_id?: string +} + +function normalizeCallID(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined + } + + const trimmed = value.trim() + return trimmed === "" ? undefined : trimmed +} + +export function resolveToolCallID(ctx: ToolCallIDCarrier): string | undefined { + const resolved = normalizeCallID(ctx.callID) ?? normalizeCallID(ctx.callId) ?? normalizeCallID(ctx.call_id) + + if (!resolved) { + log("[tool-metadata-store] Missing tool call ID for metadata correlation") + } + + return resolved +} diff --git a/src/features/tool-metadata-store/task-metadata-contract.test.ts b/src/features/tool-metadata-store/task-metadata-contract.test.ts new file mode 100644 index 000000000..0b69fc13e --- /dev/null +++ b/src/features/tool-metadata-store/task-metadata-contract.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, test } from "bun:test" + +import { buildTaskMetadataBlock, extractTaskLink, parseTaskMetadataBlock } from "./task-metadata-contract" + +describe("buildTaskMetadataBlock", () => { + test("#given only session id #when building #then it preserves the frozen block format", () => { + // given + const link = { sessionId: "ses_abc" } + + // when + const block = buildTaskMetadataBlock(link) + + // then + expect(block).toBe("\nsession_id: ses_abc\n") + }) + + test("#given extended task metadata #when building #then it emits optional lines in order", () => { + // given + const link = { + sessionId: "ses_bg_123", + taskId: "ses_bg_123", + backgroundTaskId: "bg_123", + agent: "explore", + category: "quick", + } + + // when + const block = buildTaskMetadataBlock(link) + + // then + expect(block).toBe( + "\nsession_id: ses_bg_123\ntask_id: ses_bg_123\nbackground_task_id: bg_123\nsubagent: explore\ncategory: quick\n" + ) + }) +}) + +describe("parseTaskMetadataBlock", () => { + test("#given a task metadata block #when parsing #then it extracts the structured link", () => { + // given + const text = "\nsession_id: ses_sync_123\ntask_id: task_123\nbackground_task_id: bg_123\nsubagent: oracle\ncategory: deep\n" + + // when + const parsed = parseTaskMetadataBlock(text) + + // then + expect(parsed).toEqual({ + sessionId: "ses_sync_123", + taskId: "task_123", + backgroundTaskId: "bg_123", + agent: "oracle", + category: "deep", + }) + }) + + test("#given text without metadata #when parsing #then it returns an empty link", () => { + // given + const text = "Task completed without metadata" + + // when + const parsed = parseTaskMetadataBlock(text) + + // then + expect(parsed).toEqual({}) + }) +}) + +describe("extractTaskLink", () => { + test("#given metadata session aliases #when extracting #then metadata wins over output text", () => { + // given + const metadata = { + sessionID: "ses_meta_123", + task_id: "task_meta_123", + background_task_id: "bg_meta_123", + subagent: "atlas", + category: "unspecified-high", + } + const output = "\nsession_id: ses_text_456\n" + + // when + const extracted = extractTaskLink(metadata, output) + + // then + expect(extracted).toEqual({ + sessionId: "ses_meta_123", + taskId: "task_meta_123", + backgroundTaskId: "bg_meta_123", + agent: "atlas", + category: "unspecified-high", + }) + }) + + test("#given missing metadata #when extracting #then it falls back to task metadata text", () => { + // given + const output = "Task completed.\n\n\nsession_id: ses_text_456\nsubagent: oracle\n" + + // when + const extracted = extractTaskLink(undefined, output) + + // then + expect(extracted).toEqual({ + sessionId: "ses_text_456", + agent: "oracle", + }) + }) + + test("#given explicit session id output #when extracting #then it preserves Session ID compatibility", () => { + // given + const output = "Background task launched.\n\nSession ID: ses_bg_789" + + // when + const extracted = extractTaskLink(undefined, output) + + // then + expect(extracted).toEqual({ sessionId: "ses_bg_789" }) + }) +}) diff --git a/src/features/tool-metadata-store/task-metadata-contract.ts b/src/features/tool-metadata-store/task-metadata-contract.ts new file mode 100644 index 000000000..4044482e5 --- /dev/null +++ b/src/features/tool-metadata-store/task-metadata-contract.ts @@ -0,0 +1,144 @@ +import { log } from "../../shared/logger" + +export interface TaskLink { + sessionId?: string + taskId?: string + backgroundTaskId?: string + agent?: string + category?: string +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function readString(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined + } + + const trimmed = value.trim() + return trimmed === "" ? undefined : trimmed +} + +function readSessionIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.sessionId) ?? readString(metadata.sessionID) ?? readString(metadata.session_id) +} + +function readTaskIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.taskId) ?? readString(metadata.taskID) ?? readString(metadata.task_id) +} + +function readBackgroundTaskIdFromMetadata(metadata: Record): string | undefined { + return readString(metadata.backgroundTaskId) + ?? readString(metadata.backgroundTaskID) + ?? readString(metadata.background_task_id) +} + +function readAgentFromMetadata(metadata: Record): string | undefined { + return readString(metadata.agent) ?? readString(metadata.subagent) +} + +function readCategoryFromMetadata(metadata: Record): string | undefined { + return readString(metadata.category) +} + +function extractTaskMetadataContent(text: string): string | undefined { + const blocks = [...text.matchAll(/([\s\S]*?)<\/task_metadata>/gi)] + return blocks.at(-1)?.[1] +} + +function extractExplicitSessionId(text: string): string | undefined { + const matches = [...text.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)] + return matches.at(-1)?.[1] +} + +export function buildTaskMetadataBlock(link: TaskLink): string { + const lines: string[] = [] + + if (link.sessionId) { + lines.push(`session_id: ${link.sessionId}`) + } + if (link.taskId) { + lines.push(`task_id: ${link.taskId}`) + } + if (link.backgroundTaskId) { + lines.push(`background_task_id: ${link.backgroundTaskId}`) + } + if (link.agent) { + lines.push(`subagent: ${link.agent}`) + } + if (link.category) { + lines.push(`category: ${link.category}`) + } + + return `\n${lines.join("\n")}\n` +} + +export function parseTaskMetadataBlock(text: string): TaskLink { + const blockContent = extractTaskMetadataContent(text) ?? text + const lines = blockContent + .split("\n") + .map(line => line.trim()) + .filter(Boolean) + + const parsed: TaskLink = {} + + for (const line of lines) { + const separatorIndex = line.indexOf(":") + if (separatorIndex === -1) { + continue + } + + const key = line.slice(0, separatorIndex).trim().toLowerCase() + const value = readString(line.slice(separatorIndex + 1)) + + if (!value) { + continue + } + + if (key === "session_id") { + parsed.sessionId = value + } else if (key === "task_id") { + parsed.taskId = value + } else if (key === "background_task_id") { + parsed.backgroundTaskId = value + } else if (key === "subagent" || key === "agent") { + parsed.agent = value + } else if (key === "category") { + parsed.category = value + } + } + + return parsed +} + +export function extractTaskLink(metadata: unknown, outputText: string): TaskLink { + if (isRecord(metadata)) { + const metadataLink: TaskLink = { + sessionId: readSessionIdFromMetadata(metadata), + taskId: readTaskIdFromMetadata(metadata), + backgroundTaskId: readBackgroundTaskIdFromMetadata(metadata), + agent: readAgentFromMetadata(metadata), + category: readCategoryFromMetadata(metadata), + } + + if (metadataLink.sessionId || metadataLink.taskId || metadataLink.backgroundTaskId || metadataLink.agent || metadataLink.category) { + return metadataLink + } + } + + const parsed = parseTaskMetadataBlock(outputText) + if (parsed.sessionId || parsed.taskId || parsed.backgroundTaskId || parsed.agent || parsed.category) { + log("[tool-metadata-store] Falling back to parsing") + return parsed + } + + const explicitSessionId = extractExplicitSessionId(outputText) + if (explicitSessionId) { + log("[tool-metadata-store] Falling back to explicit Session ID parsing") + return { sessionId: explicitSessionId } + } + + return {} +} diff --git a/src/generated/model-capabilities.generated.json b/src/generated/model-capabilities.generated.json index 4d51ec888..b307aeadd 100644 --- a/src/generated/model-capabilities.generated.json +++ b/src/generated/model-capabilities.generated.json @@ -1,223 +1,12 @@ { - "generatedAt": "2026-03-25T13:44:08.677Z", + "generatedAt": "2026-04-17T05:38:15.814Z", "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", + "qwen3-235b-a22b": { + "id": "qwen3-235b-a22b", "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, + "temperature": true, "toolCall": true, "modalities": { "input": [ @@ -229,172 +18,18 @@ }, "limit": { "context": 128000, - "output": 16384, - "input": 128000 - }, - "temperature": true + "output": 32000 + } }, - "openai/whisper-large-v3": { - "id": "openai/whisper-large-v3", - "family": "whisper", + "grok-4.1": { + "id": "grok-4.1", "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" + "text", + "image" ], "output": [ "text" @@ -402,234 +37,11 @@ }, "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", + "minimax-m2": { + "id": "MiniMax-M2", "reasoning": true, "temperature": true, "toolCall": true, @@ -642,201 +54,14 @@ ] }, "limit": { - "context": 1000000, - "output": 128000 + "context": 196608, + "output": 128000, + "input": 200000 }, - "family": "mimo" + "family": "minimax" }, - "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", + "grok-4-1-fast-reasoning": { + "id": "grok-4-1-fast-reasoning", "reasoning": true, "temperature": true, "toolCall": true, @@ -850,108 +75,34 @@ ] }, "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" - ] + "context": 128000, + "output": 8192, + "input": 128000 }, - "limit": { - "context": 256000, - "output": 64000 - } + "family": "grok" }, - "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", + "gemini-2.5-flash-nothink": { + "id": "gemini-2.5-flash-nothink", + "family": "gemini-flash", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "pdf" + "image" ], "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, + "context": 1000000, "output": 65536 - }, - "family": "deepseek" + } }, - "moonshotai/kimi-k2-0905": { - "id": "moonshotai/kimi-k2-0905", + "kimi-k2-0905-preview": { + "id": "kimi-k2-0905-preview", "reasoning": false, "temperature": true, "toolCall": true, @@ -964,52 +115,13 @@ ] }, "limit": { - "context": 131072, - "output": 26215 + "context": 262144, + "output": 262144 }, "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", + "claude-opus-4-5-20251101": { + "id": "claude-opus-4-5-20251101", "reasoning": true, "temperature": true, "toolCall": true, @@ -1017,223 +129,7 @@ "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" + "pdf" ], "output": [ "text" @@ -1241,3830 +137,13 @@ }, "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, + "output": 64000, "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", + "gemini-2.5-flash-lite-preview-09-2025": { + "id": "gemini-2.5-flash-lite-preview-09-2025", "reasoning": true, "temperature": true, "toolCall": true, @@ -5081,1150 +160,11 @@ ] }, "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" - ] + "context": 1048576, + "output": 65536, + "input": 1048756 }, - "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 - } + "family": "gemini-flash-lite" }, "qwen3-235b-a22b-instruct-2507": { "id": "qwen3-235b-a22b-instruct-2507", @@ -6240,193 +180,14 @@ ] }, "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, + "context": 262000, "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 - } + "family": "qwen" }, - "gemini-2.5-flash": { - "id": "gemini-2.5-flash", - "reasoning": true, + "mistral-large-2512": { + "id": "mistral-large-2512", + "reasoning": false, "temperature": true, "toolCall": false, "modalities": { @@ -6439,14 +200,13 @@ ] }, "limit": { - "context": 1048756, - "output": 65536, - "input": 1048756 + "context": 262144, + "output": 16384 }, - "family": "gemini-flash" + "family": "mistral" }, - "deepseek-v3.1": { - "id": "deepseek-v3.1", + "glm-4.7": { + "id": "glm-4.7", "reasoning": true, "temperature": true, "toolCall": true, @@ -6458,54 +218,91 @@ "text" ] }, + "limit": { + "context": 204800, + "output": 131072 + }, + "family": "glm" + }, + "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 + } + }, + "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 + } + }, + "deepseek-chat": { + "id": "deepseek-chat", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, "limit": { "context": 131072, - "output": 131072 - }, - "family": "deepseek" + "output": 8192, + "input": 128000 + } }, - "doubao-seed-1.6": { - "id": "doubao-seed-1.6", + "deepseek-v3.2-thinking": { + "id": "deepseek-v3.2-thinking", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "video" + "text" ], "output": [ "text" ] }, "limit": { - "context": 256000, - "output": 32000 + "context": 128000, + "output": 128000 } }, - "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", + "gpt-5-thinking": { + "id": "gpt-5-thinking", "reasoning": true, "temperature": true, "toolCall": true, @@ -6519,32 +316,12 @@ ] }, "limit": { - "context": 200000, - "output": 32000 + "context": 400000, + "output": 128000 } }, - "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", + "gemini-3-flash-preview": { + "id": "gemini-3-flash-preview", "reasoning": true, "temperature": true, "toolCall": true, @@ -6553,8 +330,72 @@ "text", "image", "video", - "pdf", - "audio" + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + }, + "family": "gemini-flash" + }, + "qwen-plus": { + "id": "qwen-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000, + "input": 995904 + } + }, + "gpt-5-mini": { + "id": "gpt-5-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 272000 + }, + "family": "gpt-mini" + }, + "gemini-3-pro-preview": { + "id": "gemini-3-pro-preview", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" ], "output": [ "text" @@ -6562,50 +403,157 @@ }, "limit": { "context": 1000000, + "output": 65000, + "input": 128000 + }, + "family": "gemini-pro" + }, + "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 + } + }, + "claude-sonnet-4-5-20250929": { + "id": "claude-sonnet-4-5-20250929", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 64000, + "input": 1000000 + }, + "family": "claude-sonnet" + }, + "qwen-flash": { + "id": "qwen-flash", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + }, + "family": "qwen" + }, + "gemini-2.5-pro": { + "id": "gemini-2.5-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 128000 + } + }, + "grok-4-1-fast-non-reasoning": { + "id": "grok-4-1-fast-non-reasoning", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 128000 + }, + "family": "grok" + }, + "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 } }, - "deepseek-r1-0528": { - "id": "deepseek-r1-0528", + "gpt-5.2": { + "id": "gpt-5.2", "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" + "image" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "output": 16000 - } + "context": 400000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" }, - "gemini-3.0-pro-image-preview": { - "id": "gemini-3.0-pro-image-preview", + "gemini-3-pro-image-preview": { + "id": "gemini-3-pro-image-preview", "reasoning": false, "temperature": true, "toolCall": false, @@ -6620,54 +568,15 @@ ] }, "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, + "context": 65536, + "output": 32768, "input": 1048756 }, - "family": "gemini-flash-lite" + "family": "gemini" }, - "claude-3.5-haiku": { - "id": "claude-3.5-haiku", + "qwen-max-latest": { + "id": "qwen-max-latest", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": true, @@ -6680,184 +589,11 @@ "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, @@ -6879,8 +615,153 @@ }, "family": "gemini-flash" }, - "minimax-m1": { - "id": "MiniMax-M1", + "glm-4.5": { + "id": "glm-4.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm" + }, + "gemini-2.5-flash": { + "id": "gemini-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "audio", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536, + "input": 1048756 + } + }, + "gpt-5.2-chat-latest": { + "id": "gpt-5.2-chat-latest", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16400 + }, + "family": "gpt" + }, + "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 + } + }, + "minimax-m2.1": { + "id": "MiniMax-M2.1", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + }, + "family": "minimax" + }, + "gpt-5.1": { + "id": "gpt-5.1", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text", + "image", + "audio" + ] + }, + "limit": { + "context": 272000, + "output": 128000, + "input": 272000 + }, + "family": "gpt" + }, + "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" + }, + "deepseek-reasoner": { + "id": "deepseek-reasoner", + "family": "deepseek-thinking", "reasoning": false, "temperature": true, "toolCall": false, @@ -6892,93 +773,34 @@ "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 + "output": 64000, + "input": 64000 } }, - "doubao-seed-2.0-code": { - "id": "doubao-seed-2.0-code", + "grok-4-fast-reasoning": { + "id": "grok-4-fast-reasoning", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "video" + "image" ], "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" - ] + "context": 2000000, + "output": 30000 }, - "limit": { - "context": 126000, - "output": 32000 - } + "family": "grok" }, - "claude-4.5-opus": { - "id": "claude-4.5-opus", + "claude-opus-4-1-20250805-thinking": { + "id": "claude-opus-4-1-20250805-thinking", "reasoning": true, "temperature": true, "toolCall": true, @@ -6993,74 +815,12 @@ }, "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 + "output": 32000 } }, "qwen3-30b-a3b": { "id": "qwen3-30b-a3b", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": true, @@ -7076,11 +836,31 @@ "limit": { "context": 41000, "output": 41000 - }, - "family": "qwen" + } }, - "gpt-oss-20b": { - "id": "gpt-oss-20b", + "glm-4.5v": { + "id": "glm-4.5v", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16384 + }, + "family": "glm" + }, + "glm-4.6": { + "id": "glm-4.6", "reasoning": true, "temperature": true, "toolCall": true, @@ -7093,55 +873,14 @@ ] }, "limit": { - "context": 131072, + "context": 204800, "output": 131072 }, - "family": "gpt-oss" + "family": "glm" }, - "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, + "gemini-2.5-flash-preview-09-2025": { + "id": "gemini-2.5-flash-preview-09-2025", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -7158,196 +897,13 @@ }, "limit": { "context": 1048576, - "output": 8192 + "output": 65536, + "input": 1048756 }, "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", + "glm-4.6v": { + "id": "glm-4.6v", "reasoning": true, "temperature": true, "toolCall": true, @@ -7355,7 +911,6 @@ "input": [ "text", "image", - "audio", "video" ], "output": [ @@ -7363,33 +918,13 @@ ] }, "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" - ] + "context": 128000, + "output": 32768 }, - "limit": { - "context": 2000000, - "output": 131072, - "input": 2000000 - }, - "family": "grok" + "family": "glm" }, - "x-ai/grok-4-fast-non-reasoning": { - "id": "x-ai/grok-4-fast-non-reasoning", + "claude-opus-4-1-20250805": { + "id": "claude-opus-4-1-20250805", "reasoning": true, "temperature": true, "toolCall": true, @@ -7397,3051 +932,21 @@ "input": [ "text", "image", - "audio", - "video" + "pdf" ], "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, + "context": 200000, + "output": 32000, "input": 200000 }, - "temperature": true + "family": "claude-opus" }, - "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", + "gpt-5.1-chat-latest": { + "id": "gpt-5.1-chat-latest", "reasoning": true, "temperature": false, "toolCall": true, @@ -10454,663 +959,15 @@ "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 - } + "family": "gpt-codex" }, - "gpt-5.2": { - "id": "gpt-5.2", - "family": "gpt", + "claude-haiku-4-5-20251001": { + "id": "claude-haiku-4-5-20251001", "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": { @@ -11126,12 +983,13 @@ "limit": { "context": 200000, "output": 64000, - "input": 128000 - } + "input": 200000 + }, + "family": "claude-haiku" }, - "glm-4.7-free": { - "id": "glm-4.7-free", - "family": "glm-free", + "minimax-m1": { + "id": "MiniMax-M1", + "family": "minimax", "reasoning": true, "temperature": true, "toolCall": true, @@ -11143,813 +1001,36 @@ "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 + "output": 80000, + "input": 1000000 } }, - "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", + "qwen3-coder-480b-a35b-instruct": { + "id": "qwen3-coder-480b-a35b-instruct", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "audio", - "video", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 1048576, + "context": 262000, "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 - } + "family": "qwen" }, - "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", + "doubao-seed-code-preview-251028": { + "id": "doubao-seed-code-preview-251028", "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", @@ -11960,321 +1041,16 @@ ] }, "limit": { - "context": 400000, - "output": 128000, - "input": 400000 + "context": 256000, + "output": 32000 } }, - "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", + "gpt-4.1-nano": { + "id": "gpt-4.1-nano", "family": "gpt-nano", "reasoning": false, "temperature": true, "toolCall": true, - "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": true, "modalities": { "input": [ "text", @@ -12286,699 +1062,12 @@ }, "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, + "deepseek-v3.2": { + "id": "deepseek-v3.2", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -12991,554 +1080,14 @@ }, "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 - } + "family": "deepseek" }, - "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", + "gpt-5-pro": { + "id": "gpt-5-pro", "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, + "temperature": false, "toolCall": true, "modalities": { "input": [ @@ -13550,1192 +1099,11 @@ ] }, "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" - ] + "context": 400000, + "output": 272000, + "input": 272000 }, - "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 - } + "family": "gpt-pro" }, "gpt-4o": { "id": "gpt-4o", @@ -14758,162 +1126,8 @@ "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", + "gpt-5": { + "id": "gpt-5", "reasoning": true, "temperature": false, "toolCall": true, @@ -14930,429 +1144,28 @@ "context": 272000, "output": 128000, "input": 272000 - } + }, + "family": "gpt" }, - "grok-4-fast-non-reasoning": { - "id": "grok-4-fast-non-reasoning", - "family": "grok", - "reasoning": false, + "claude-sonnet-4-5-20250929-thinking": { + "id": "claude-sonnet-4-5-20250929-thinking", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "pdf" ], "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 + "context": 1000000, + "output": 64000, + "input": 1000000 } }, "gpt-4.1": { @@ -15376,85 +1189,52 @@ "input": 64000 } }, - "model-router": { - "id": "model-router", - "family": "model-router", + "kimi-k2-thinking": { + "id": "kimi-k2-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + }, + "family": "kimi-thinking" + }, + "gemini-2.0-flash-lite": { + "id": "gemini-2.0-flash-lite", + "family": "gemini-flash-lite", "reasoning": false, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "output": 16384 + "context": 1048576, + "output": 8192, + "input": 1000000 } }, - "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", + "gpt-4.1-mini": { + "id": "gpt-4.1-mini", + "family": "gpt-mini", "reasoning": false, "temperature": true, "toolCall": true, @@ -15472,560 +1252,11 @@ "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", + "grok-4-fast-non-reasoning": { + "id": "grok-4-fast-non-reasoning", "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", @@ -16038,31 +1269,12 @@ "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 + "family": "grok" }, - "gpt-4o-mini": { - "id": "gpt-4o-mini", - "family": "gpt-mini", - "reasoning": false, + "doubao-seed-1-6-thinking-250715": { + "id": "doubao-seed-1-6-thinking-250715", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -16075,111 +1287,32 @@ ] }, "limit": { - "context": 128000, + "context": 256000, + "output": 16000 + } + }, + "ministral-14b-2512": { + "id": "ministral-14b-2512", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, "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 - } + "family": "mistral" }, - "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", + "qwen3-coder-plus": { + "id": "qwen3-coder-plus", "family": "qwen", "reasoning": false, "temperature": true, @@ -16194,11 +1327,72 @@ }, "limit": { "context": 1000000, - "output": 65536 + "output": 66000 } }, - "qwen3-vl-30b-a3b": { - "id": "qwen3-vl-30b-a3b", + "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 + } + }, + "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 + } + }, + "qwen3-8b": { + "id": "qwen3-8b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "qwen3.5-397b-a17b": { + "id": "qwen3.5-397b-a17b", "family": "qwen", "reasoning": true, "temperature": true, @@ -16212,9 +1406,254 @@ "text" ] }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "qwq-plus": { + "id": "qwq-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, "limit": { "context": 131072, - "output": 32768 + "output": 8192 + } + }, + "qwen-vl-plus": { + "id": "qwen-vl-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "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 + } + }, + "qwen3-32b": { + "id": "qwen3-32b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen-max": { + "id": "qwen-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000, + "input": 32000 + } + }, + "qwen-omni-turbo": { + "id": "qwen-omni-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "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 + } + }, + "qwen3.6-plus": { + "id": "qwen3.6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen3-max": { + "id": "qwen3-max", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32800 + } + }, + "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 + } + }, + "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-vl-235b-a22b": { + "id": "qwen3-vl-235b-a22b", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 } }, "qwen3-asr-flash": { @@ -16236,8 +1675,66 @@ "output": 4096 } }, - "qwen-max": { - "id": "qwen-max", + "qwen3-next-80b-a3b-thinking": { + "id": "qwen3-next-80b-a3b-thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "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 + } + }, + "qwen-vl-max": { + "id": "qwen-vl-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32000 + } + }, + "qwen3-coder-flash": { + "id": "qwen3-coder-flash", "family": "qwen", "reasoning": false, "temperature": true, @@ -16251,9 +1748,8 @@ ] }, "limit": { - "context": 131072, - "output": 8192, - "input": 32000 + "context": 1000000, + "output": 65536 } }, "qwen2-5-7b-instruct": { @@ -16275,26 +1771,6 @@ "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", @@ -16314,10 +1790,10 @@ "output": 8192 } }, - "qwen3-8b": { - "id": "qwen3-8b", + "qwen2-5-32b-instruct": { + "id": "qwen2-5-32b-instruct", "family": "qwen", - "reasoning": true, + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { @@ -16333,9 +1809,69 @@ "output": 8192 } }, - "qvq-max": { - "id": "qvq-max", - "family": "qvq", + "qwen3-next-80b-a3b-instruct": { + "id": "qwen3-next-80b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 129024, + "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 + } + }, + "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 + } + }, + "qwen3-vl-30b-a3b": { + "id": "qwen3-vl-30b-a3b", + "family": "qwen", "reasoning": true, "temperature": true, "toolCall": true, @@ -16350,10 +1886,88 @@ }, "limit": { "context": 131072, + "output": 32768 + } + }, + "qwen3-vl-plus": { + "id": "qwen3-vl-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "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": 262000, "output": 8192, "input": 128000 } }, + "qwen-turbo": { + "id": "qwen-turbo", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 8192, + "input": 1000000 + } + }, + "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 + } + }, "qwen2-5-omni-7b": { "id": "qwen2-5-omni-7b", "family": "qwen", @@ -16377,122 +1991,16 @@ "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", + "qwen3.5-plus": { + "id": "qwen3.5-plus", "family": "qwen", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" @@ -16500,114 +2008,11 @@ }, "limit": { "context": 1000000, - "output": 32768, - "input": 995904 + "output": 65536 } }, - "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", + "qwen2-5-vl-72b-instruct": { + "id": "qwen2-5-vl-72b-instruct", "family": "qwen", "reasoning": false, "temperature": true, @@ -16621,1061 +2026,15 @@ "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, + "qvq-max": { + "id": "qvq-max", + "family": "qvq", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -17689,69 +2048,13 @@ }, "limit": { "context": 131072, - "output": 8192 + "output": 8192, + "input": 128000 } }, - "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", + "qwen3-14b": { + "id": "qwen3-14b", "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, @@ -17764,406 +2067,13 @@ ] }, "limit": { - "context": 204800, - "output": 131072 + "context": 131072, + "output": 8192 } }, - "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", + "qwen3-embedding-8b": { + "id": "qwen3-embedding-8b", + "family": "qwen", "reasoning": false, "temperature": false, "toolCall": false, @@ -18176,13 +2086,13 @@ ] }, "limit": { - "context": 8000, - "output": 3072 + "context": 32768, + "output": 4096 } }, - "devstral-small-2505": { - "id": "devstral-small-2505", - "family": "devstral", + "llama-3.3-70b-instruct": { + "id": "llama-3.3-70b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": true, @@ -18196,11 +2106,49 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 32768 } }, - "pixtral-12b": { - "id": "pixtral-12b", + "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 + } + }, + "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": 131072, + "output": 8192 + } + }, + "pixtral-12b-2409": { + "id": "pixtral-12b-2409", "family": "pixtral", "reasoning": false, "temperature": true, @@ -18216,18 +2164,38 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 4096 } }, - "open-mixtral-8x7b": { - "id": "open-mixtral-8x7b", - "family": "mixtral", + "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 + } + }, + "voxtral-small-24b-2507": { + "id": "voxtral-small-24b-2507", + "family": "voxtral", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "audio" ], "output": [ "text" @@ -18235,12 +2203,12 @@ }, "limit": { "context": 32000, - "output": 32000 + "output": 16384 } }, - "pixtral-large-latest": { - "id": "pixtral-large-latest", - "family": "pixtral", + "gemma-3-27b-it": { + "id": "gemma-3-27b-it", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": true, @@ -18254,16 +2222,17 @@ ] }, "limit": { - "context": 128000, - "output": 128000 + "context": 131072, + "output": 8192, + "input": 32768 } }, - "devstral-2512": { - "id": "devstral-2512", - "family": "devstral", + "bge-multilingual-gemma2": { + "id": "bge-multilingual-gemma2", + "family": "gemma", "reasoning": false, - "temperature": true, - "toolCall": true, + "temperature": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -18273,52 +2242,12 @@ ] }, "limit": { - "context": 262000, - "output": 262000 + "context": 8191, + "output": 3072 } }, - "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", + "mistral-small-3.2-24b-instruct-2506": { + "id": "mistral-small-3.2-24b-instruct-2506", "family": "mistral-small", "reasoning": false, "temperature": true, @@ -18333,53 +2262,14 @@ ] }, "limit": { - "context": 128000, - "output": 16384 + "context": 131072, + "output": 131072 } }, - "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, + "gpt-oss-120b": { + "id": "gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, "temperature": true, "toolCall": true, "modalities": { @@ -18395,449 +2285,27 @@ "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", + "mistral-nemo-instruct-2407": { + "id": "mistral-nemo-instruct-2407", + "family": "mistral-nemo", "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image" + "text" ], "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, + "context": 65536, "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", + "llama-3.1-8b-instruct": { + "id": "llama-3.1-8b-instruct", "family": "llama", "reasoning": false, "temperature": true, @@ -18852,54 +2320,13 @@ }, "limit": { "context": 128000, - "output": 4096 + "output": 2048 } }, - "qwen/qwen2.5-72b-instruct": { - "id": "Qwen/Qwen2.5-72B-Instruct", - "family": "qwen", + "glm-4-flash": { + "id": "glm-4-flash", "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, + "toolCall": false, "modalities": { "input": [ "text" @@ -18910,75 +2337,37 @@ }, "limit": { "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "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 } }, - "accounts/fireworks/models/glm-4p7": { - "id": "accounts/fireworks/models/glm-4p7", - "family": "glm", + "claude-opus-4-thinking:32000": { + "id": "claude-opus-4-thinking:32000", "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" + "text", + "image", + "pdf" ], "output": [ "text" @@ -18986,131 +2375,38 @@ }, "limit": { "context": 200000, - "output": 200000 + "input": 200000, + "output": 32000 } }, - "accounts/fireworks/models/glm-4p5-air": { - "id": "accounts/fireworks/models/glm-4p5-air", - "family": "glm-air", + "gemini-2.5-pro-preview-05-06": { + "id": "gemini-2.5-pro-preview-05-06", "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" + "audio", + "video", + "pdf" ], "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" - ] + "context": 1048576, + "input": 1048756, + "output": 65536 }, - "limit": { - "context": 256000, - "output": 256000 - } + "family": "gemini-pro", + "temperature": true }, - "accounts/fireworks/models/glm-4p5": { - "id": "accounts/fireworks/models/glm-4p5", - "family": "glm", - "reasoning": true, - "temperature": true, - "toolCall": true, + "grok-3-mini-fast-beta": { + "id": "grok-3-mini-fast-beta", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19121,32 +2417,13 @@ }, "limit": { "context": 131072, + "input": 131072, "output": 131072 } }, - "accounts/fireworks/models/gpt-oss-20b": { - "id": "accounts/fireworks/models/gpt-oss-20b", - "family": "gpt-oss", + "command-a-reasoning-08-2025": { + "id": "command-a-reasoning-08-2025", "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": [ @@ -19159,14 +2436,15 @@ "limit": { "context": 256000, "input": 256000, - "output": 256000 - } + "output": 32000 + }, + "family": "command-a", + "temperature": true }, - "step-2-16k": { - "id": "step-2-16k", - "reasoning": true, - "temperature": true, - "toolCall": true, + "brave": { + "id": "brave", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19176,16 +2454,33 @@ ] }, "limit": { - "context": 16384, - "input": 16384, + "context": 8192, + "input": 8192, "output": 8192 } }, - "step-1-32k": { - "id": "step-1-32k", - "reasoning": true, - "temperature": true, - "toolCall": true, + "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-nova": { + "id": "Llama-3.3-70B-Nova", + "reasoning": false, + "toolCall": false, "modalities": { "input": [ "text" @@ -19197,13298 +2492,11 @@ "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", + "gemini-exp-1206": { + "id": "gemini-exp-1206", "reasoning": false, "toolCall": false, "modalities": { @@ -32506,27 +2514,8 @@ "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", + "auto-model-basic": { + "id": "auto-model-basic", "reasoning": false, "toolCall": false, "modalities": { @@ -32538,215 +2527,13 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 16384 + "context": 1000000, + "input": 1000000, + "output": 1000000 } }, - "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", + "jamba-mini": { + "id": "jamba-mini", "reasoning": false, "toolCall": false, "modalities": { @@ -32763,8 +2550,366 @@ "output": 4096 } }, - "llama-3.3-70b-aurora-borealis": { - "id": "Llama-3.3-70B-Aurora-Borealis", + "yi-large": { + "id": "yi-large", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "output": 4096 + } + }, + "auto-model-premium": { + "id": "auto-model-premium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "azure-gpt-4o": { + "id": "azure-gpt-4o", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "deepseek-v3-0324": { + "id": "deepseek-v3-0324", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true, + "family": "deepseek" + }, + "claude-3-5-haiku-20241022": { + "id": "claude-3-5-haiku-20241022", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "family": "claude-haiku", + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "fastgpt": { + "id": "fastgpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "claude-3-5-sonnet-20241022": { + "id": "claude-3-5-sonnet-20241022", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 8192 + }, + "family": "claude-sonnet", + "temperature": true + }, + "yi-medium-200k": { + "id": "yi-medium-200k", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "llama-3.3+(3v3.3)-70b-tenyxchat-daybreakstorywriter": { + "id": "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter", "reasoning": false, "toolCall": false, "modalities": { @@ -32800,8 +2945,64 @@ "output": 16384 } }, - "llama-3.3-70b-magnum-v4-se": { - "id": "Llama-3.3-70B-Magnum-v4-SE", + "glm-z1-air": { + "id": "glm-z1-air", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "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 + } + }, + "glm-4-air": { + "id": "glm-4-air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "llama-3.3-70b-miraifanfare": { + "id": "Llama-3.3-70B-MiraiFanfare", "reasoning": false, "toolCall": false, "modalities": { @@ -32818,44 +3019,119 @@ "output": 16384 } }, - "kat-coder-pro-v1": { - "id": "KAT-Coder-Pro-V1", - "reasoning": false, + "gemini-2.0-flash-thinking-exp-01-21": { + "id": "gemini-2.0-flash-thinking-exp-01-21", + "reasoning": true, "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "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, + "context": 1000000, + "input": 1000000, "output": 8192 } }, - "jamba-large-1.7": { - "id": "jamba-large-1.7", + "magistral-small-2506": { + "id": "Magistral-Small-2506", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "doubao-1.5-pro-32k": { + "id": "doubao-1.5-pro-32k", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 32000, + "output": 12000 + }, + "temperature": true + }, + "venice-uncensored:web": { + "id": "venice-uncensored:web", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "input": 80000, + "output": 16384 + } + }, + "glm-4": { + "id": "glm-4", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "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 + } + }, + "jamba-large-1.6": { + "id": "jamba-large-1.6", "reasoning": false, "toolCall": false, "modalities": { @@ -32872,8 +3148,857 @@ "output": 4096 } }, - "mercury-coder-small": { - "id": "mercury-coder-small", + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "universal-summarizer": { + "id": "universal-summarizer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "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 + } + }, + "sarvan-medium": { + "id": "sarvan-medium", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "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 + } + }, + "gemini-2.5-flash-preview-05-20": { + "id": "gemini-2.5-flash-preview-05-20", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048000, + "output": 65536 + }, + "family": "gemini-flash", + "temperature": true + }, + "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-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 + } + }, + "qwen3-vl-235b-a22b-thinking": { + "id": "qwen3-vl-235b-a22b-thinking", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 32768, + "output": 32768 + }, + "family": "qwen", + "temperature": true + }, + "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 + } + }, + "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-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 + } + }, + "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-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-4-plus-0111": { + "id": "glm-4-plus-0111", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "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 + } + }, + "deepseek-r1-sambanova": { + "id": "deepseek-r1-sambanova", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + } + }, + "deepseek-r1": { + "id": "deepseek-r1", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 128000, + "output": 163840 + }, + "family": "deepseek-thinking", + "temperature": true + }, + "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 + } + }, + "sonar-pro": { + "id": "sonar-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "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 + } + }, + "deepseek-chat-cheaper": { + "id": "deepseek-chat-cheaper", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "hunyuan-t1-latest": { + "id": "hunyuan-t1-latest", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 16384 + } + }, + "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 + } + }, + "asi1-mini": { + "id": "asi1-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "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 + } + }, + "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-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-nidum-uncensored": { + "id": "Gemma-3-27B-Nidum-Uncensored", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 96000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "llama-3.3-70b-forgotten-safeword-3.6": { + "id": "Llama-3.3-70B-Forgotten-Safeword-3.6", "reasoning": false, "toolCall": false, "modalities": { @@ -32909,234 +4034,16 @@ "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", + "gemini-2.5-pro-preview-06-05": { + "id": "gemini-2.5-pro-preview-06-05", "reasoning": true, "toolCall": true, "modalities": { "input": [ "text", "image", + "audio", + "video", "pdf" ], "output": [ @@ -33144,474 +4051,13 @@ ] }, "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" - ] + "context": 1048576, + "input": 1048756, + "output": 65536 }, - "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", + "family": "gemini-pro", "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, @@ -33630,429 +4076,6 @@ "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, @@ -34071,181 +4094,33 @@ "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", + "gemini-2.5-flash-lite-preview-06-17": { + "id": "gemini-2.5-flash-lite-preview-06-17", "reasoning": true, "toolCall": true, "modalities": { "input": [ "text", - "image" + "image", + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 1048756, + "context": 1048576, "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 - } + "family": "gemini-flash-lite", + "temperature": true }, - "claude-opus-4-1-thinking": { - "id": "claude-opus-4-1-thinking", + "sonar-deep-research": { + "id": "sonar-deep-research", "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": [ @@ -34256,13 +4131,15 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 - } + "context": 127000, + "input": 60000, + "output": 4096 + }, + "temperature": true, + "family": "sonar-deep-research" }, - "llama-3.3-70b-the-omega-directive-unslop-v2.1": { - "id": "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1", + "llama-3.3-70b-geneticlemonade-unleashed-v3": { + "id": "Llama-3.3-70B-GeneticLemonade-Unleashed-v3", "reasoning": false, "toolCall": false, "modalities": { @@ -34279,281 +4156,6 @@ "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, @@ -34572,28 +4174,8 @@ "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", + "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": { @@ -34605,74 +4187,15 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 1000000 + "context": 32768, + "input": 32768, + "output": 16384 } }, - "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", + "qwen3-30b-a3b-instruct-2507": { + "id": "qwen3-30b-a3b-instruct-2507", "reasoning": false, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text" @@ -34682,616 +4205,12 @@ ] }, "limit": { - "context": 256000, + "context": 262000, "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 - } + "family": "qwen" }, "gemini-2.5-flash-preview-09-2025-thinking": { "id": "gemini-2.5-flash-preview-09-2025-thinking", @@ -35313,115 +4232,6 @@ "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, @@ -35441,85 +4251,8 @@ "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", + "ernie-4.5-8k-preview": { + "id": "ernie-4.5-8k-preview", "reasoning": false, "toolCall": false, "modalities": { @@ -35533,12 +4266,30 @@ "limit": { "context": 8000, "input": 8000, - "output": 4096 + "output": 16384 } }, - "azure-gpt-4o-mini": { - "id": "azure-gpt-4o-mini", + "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 + } + }, + "gemini-3-pro-preview-thinking": { + "id": "gemini-3-pro-preview-thinking", + "reasoning": true, "toolCall": true, "modalities": { "input": [ @@ -35549,14 +4300,72 @@ "text" ] }, + "limit": { + "context": 1048756, + "input": 1048756, + "output": 65536 + } + }, + "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 + } + }, + "v0-1.5-lg": { + "id": "v0-1.5-lg", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512000, + "input": 1000000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "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 } }, - "deepseek-math-v2": { - "id": "deepseek-math-v2", + "kat-coder-pro-v1": { + "id": "KAT-Coder-Pro-V1", "reasoning": false, "toolCall": false, "modalities": { @@ -35568,50 +4377,14 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 65536 + "context": 256000, + "input": 256000, + "output": 32768 } }, - "glm-4-long": { - "id": "glm-4-long", + "claude-3-5-sonnet-20240620": { + "id": "claude-3-5-sonnet-20240620", "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": [ @@ -35626,45 +4399,10 @@ "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" - ] + "output": 8192 }, - "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 - } + "family": "claude-sonnet", + "temperature": true }, "claude-opus-4-1-thinking:8192": { "id": "claude-opus-4-1-thinking:8192", @@ -35686,8 +4424,26 @@ "output": 32000 } }, - "llama-3.3-70b-damascus-r1": { - "id": "Llama-3.3-70B-Damascus-R1", + "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 + } + }, + "llama-3.3-70b-magnum-v4-se": { + "id": "Llama-3.3-70B-Magnum-v4-SE", "reasoning": false, "toolCall": false, "modalities": { @@ -35704,8 +4460,8 @@ "output": 16384 } }, - "gemma-3-27b-arliai-rpmax-v3": { - "id": "Gemma-3-27B-ArliAI-RPMax-v3", + "glm-zero-preview": { + "id": "glm-zero-preview", "reasoning": false, "toolCall": false, "modalities": { @@ -35717,14 +4473,14 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 16384 + "context": 8000, + "input": 8000, + "output": 4096 } }, - "gemini-2.5-flash-preview-05-20:thinking": { - "id": "gemini-2.5-flash-preview-05-20:thinking", - "reasoning": true, + "study_gpt-chatgpt-4o-latest": { + "id": "study_gpt-chatgpt-4o-latest", + "reasoning": false, "toolCall": false, "modalities": { "input": [ @@ -35735,52 +4491,14 @@ "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", + "glm-4-airx": { + "id": "glm-4-airx", "reasoning": false, "toolCall": false, "modalities": { @@ -35792,49 +4510,13 @@ ] }, "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, + "context": 8000, + "input": 8000, "output": 4096 } }, - "kat-coder-exp-72b-1010": { - "id": "KAT-Coder-Exp-72B-1010", + "step-2-mini": { + "id": "step-2-mini", "reasoning": false, "toolCall": false, "modalities": { @@ -35846,9 +4528,9 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 32768 + "context": 8000, + "input": 8000, + "output": 4096 } }, "gemini-2.5-flash-preview-04-17:thinking": { @@ -35870,26 +4552,8 @@ "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", + "llama-3.3-70b-mokume-gane-r1": { + "id": "Llama-3.3-70B-Mokume-Gane-R1", "reasoning": false, "toolCall": false, "modalities": { @@ -35906,8 +4570,44 @@ "output": 16384 } }, - "claude-opus-4-5-20251101:thinking": { - "id": "claude-opus-4-5-20251101:thinking", + "glm-z1-airx": { + "id": "glm-z1-airx", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 32000, + "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 + } + }, + "claude-opus-4-1-thinking": { + "id": "claude-opus-4-1-thinking", "reasoning": true, "toolCall": true, "modalities": { @@ -35944,8 +4644,8 @@ "output": 131072 } }, - "azure-o3-mini": { - "id": "azure-o3-mini", + "llama-3.3-70b-legion-v2.1": { + "id": "Llama-3.3-70B-Legion-V2.1", "reasoning": false, "toolCall": false, "modalities": { @@ -35957,49 +4657,69 @@ ] }, "limit": { - "context": 200000, - "input": 200000, + "context": 32768, + "input": 32768, + "output": 16384 + } + }, + "sonar": { + "id": "sonar", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 130000, + "input": 127000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "z-image-turbo": { + "id": "z-image-turbo", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "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 } }, - "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", + "jamba-large": { + "id": "jamba-large", "reasoning": false, "toolCall": false, "modalities": { @@ -36013,29 +4733,68 @@ "limit": { "context": 256000, "input": 256000, - "output": 128000 + "output": 4096 } }, - "llama-3.3-70b-mhnnn-x1": { - "id": "Llama-3.3-70B-Mhnnn-x1", + "claude-3-7-sonnet-reasoner": { + "id": "claude-3-7-sonnet-reasoner", "reasoning": false, "toolCall": false, "modalities": { "input": [ - "text" + "text", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 32768, - "input": 32768, + "context": 128000, + "input": 128000, + "output": 8192 + } + }, + "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 } }, - "hunyuan-t1-latest": { - "id": "hunyuan-t1-latest", + "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 + } + }, + "doubao-seed-1-6-flash-250615": { + "id": "doubao-seed-1-6-flash-250615", "reasoning": false, "toolCall": false, "modalities": { @@ -36052,8 +4811,28 @@ "output": 16384 } }, - "gemma-3-27b-cardprojector-v4": { - "id": "Gemma-3-27B-CardProjector-v4", + "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-strawberrylemonade-v1.2": { + "id": "Llama-3.3-70B-Strawberrylemonade-v1.2", "reasoning": false, "toolCall": false, "modalities": { @@ -36070,8 +4849,234 @@ "output": 16384 } }, - "glm-4-flash": { - "id": "glm-4-flash", + "gemini-2.5-flash-preview-04-17": { + "id": "gemini-2.5-flash-preview-04-17", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "family": "gemini-flash", + "temperature": true + }, + "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-math-v2": { + "id": "deepseek-math-v2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "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 + } + }, + "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 + } + }, + "qwen-image": { + "id": "qwen-image", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + }, + "family": "qwen" + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "hunyuan-turbos-20250226": { + "id": "hunyuan-turbos-20250226", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 24000, + "input": 24000, + "output": 8192 + } + }, + "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 + } + }, + "glm-4-plus": { + "id": "glm-4-plus", "reasoning": false, "toolCall": false, "modalities": { @@ -36088,26 +5093,8 @@ "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", + "gemma-3-27b-big-tiger-v3": { + "id": "Gemma-3-27B-Big-Tiger-v3", "reasoning": false, "toolCall": false, "modalities": { @@ -36124,8 +5111,8 @@ "output": 16384 } }, - "yi-large": { - "id": "yi-large", + "brave-research": { + "id": "brave-research", "reasoning": false, "toolCall": false, "modalities": { @@ -36137,13 +5124,72 @@ ] }, "limit": { - "context": 32000, - "input": 32000, - "output": 4096 + "context": 16384, + "input": 16384, + "output": 16384 } }, - "exa-answer": { - "id": "exa-answer", + "hidream": { + "id": "hidream", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "qwen3-max-2026-01-23": { + "id": "qwen3-max-2026-01-23", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 65536 + }, + "family": "qwen", + "temperature": true + }, + "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 + } + }, + "exa-research-pro": { + "id": "exa-research-pro", "reasoning": false, "toolCall": false, "modalities": { @@ -36155,9 +5201,48 @@ ] }, "limit": { - "context": 4096, - "input": 4096, - "output": 4096 + "context": 16384, + "input": 16384, + "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 + } + }, + "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 } }, "gemini-2.5-pro-exp-03-25": { @@ -36179,6 +5264,1379 @@ "output": 65536 } }, + "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 + } + }, + "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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "claude-sonnet-4-20250514": { + "id": "claude-sonnet-4-20250514", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "family": "claude-sonnet", + "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 + } + }, + "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 + } + }, + "brave-pro": { + "id": "brave-pro", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 8192, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-3-7-sonnet-20250219": { + "id": "claude-3-7-sonnet-20250219", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 64000 + }, + "family": "claude-sonnet", + "temperature": true + }, + "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 + } + }, + "chroma": { + "id": "chroma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "venice-uncensored": { + "id": "venice-uncensored", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "input": 128000, + "output": 8192 + }, + "family": "venice", + "temperature": true + }, + "step-3": { + "id": "step-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "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 + } + }, + "auto-model": { + "id": "auto-model", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "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 + } + }, + "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 + } + }, + "baichuan4-air": { + "id": "Baichuan4-Air", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "kimi-thinking-preview": { + "id": "kimi-thinking-preview", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "gemini-2.5-flash-lite": { + "id": "gemini-2.5-flash-lite", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "family": "gemini-flash-lite", + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "deepseek-reasoner-cheaper": { + "id": "deepseek-reasoner-cheaper", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 65536 + } + }, + "exa-answer": { + "id": "exa-answer", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 4096, + "output": 4096 + } + }, + "v0-1.0-md": { + "id": "v0-1.0-md", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "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 + } + }, + "azure-o1": { + "id": "azure-o1", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "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 + } + }, + "azure-o3-mini": { + "id": "azure-o3-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "claude-opus-4-20250514": { + "id": "claude-opus-4-20250514", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32000 + }, + "family": "claude-opus", + "temperature": true + }, + "yi-lightning": { + "id": "yi-lightning", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 12000, + "input": 12000, + "output": 4096 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "auto-model-standard": { + "id": "auto-model-standard", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 1000000 + } + }, + "v0-1.5-md": { + "id": "v0-1.5-md", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 32000 + }, + "family": "v0", + "temperature": true + }, + "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 + } + }, + "glm-4-long": { + "id": "glm-4-long", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "baichuan-m2": { + "id": "Baichuan-M2", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "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 + }, + "sonar-reasoning-pro": { + "id": "sonar-reasoning-pro", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 127000, + "output": 16384 + }, + "family": "sonar", + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "baichuan4-turbo": { + "id": "Baichuan4-Turbo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "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 + } + }, + "inflection/inflection-3-pi": { + "id": "inflection/inflection-3-pi", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 1024 + }, + "temperature": true + }, + "inflection/inflection-3-productivity": { + "id": "inflection/inflection-3-productivity", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "input": 8000, + "output": 1024 + }, + "temperature": true + }, + "essentialai/rnj-1-instruct": { + "id": "essentialai/Rnj-1-Instruct", + "family": "rnj", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 128000, + "output": 32768 + }, + "temperature": true + }, "llm360/k2-think": { "id": "LLM360/K2-Think", "family": "kimi-thinking", @@ -36198,501 +6656,6 @@ "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", @@ -36712,8 +6675,27 @@ "output": 65535 } }, - "tee/qwen3-30b-a3b-instruct-2507": { - "id": "TEE/qwen3-30b-a3b-instruct-2507", + "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/qwen3.5-397b-a17b": { + "id": "TEE/qwen3.5-397b-a17b", "family": "qwen", "reasoning": false, "toolCall": false, @@ -36726,15 +6708,15 @@ ] }, "limit": { - "context": 262000, - "input": 262000, - "output": 32768 + "context": 258048, + "input": 258048, + "output": 65536 } }, - "tee/kimi-k2.5-thinking": { - "id": "TEE/kimi-k2.5-thinking", - "family": "kimi-thinking", - "reasoning": true, + "tee/glm-5": { + "id": "TEE/glm-5", + "family": "glm", + "reasoning": false, "toolCall": false, "modalities": { "input": [ @@ -36745,8 +6727,8 @@ ] }, "limit": { - "context": 128000, - "input": 128000, + "context": 203000, + "input": 203000, "output": 65535 } }, @@ -36770,8 +6752,46 @@ "output": 8192 } }, - "tee/deepseek-v3.2": { - "id": "TEE/deepseek-v3.2", + "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-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/deepseek-v3.1": { + "id": "TEE/deepseek-v3.1", "family": "deepseek", "reasoning": false, "toolCall": false, @@ -36786,45 +6806,7 @@ "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 + "output": 8192 } }, "tee/llama3-3-70b": { @@ -36846,6 +6828,44 @@ "output": 16384 } }, + "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/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/gemma-3-27b-it": { "id": "TEE/gemma-3-27b-it", "family": "gemma", @@ -36865,6 +6885,25 @@ "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/gpt-oss-20b": { "id": "TEE/gpt-oss-20b", "family": "gpt-oss", @@ -36884,8 +6923,103 @@ "output": 8192 } }, - "anthracite-org/magnum-v2-72b": { - "id": "anthracite-org/magnum-v2-72b", + "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.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/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/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/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 + } + }, + "cruciblelab/l3.3-70b-loki-v2.0": { + "id": "CrucibleLab/L3.3-70B-Loki-V2.0", "family": "llama", "reasoning": false, "toolCall": false, @@ -36900,6 +7034,470 @@ "limit": { "context": 16384, "input": 16384, + "output": 16384 + } + }, + "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 + } + }, + "deepseek/deepseek-prover-v2-671b": { + "id": "deepseek/deepseek-prover-v2-671b", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 160000, + "input": 160000, + "output": 160000 + }, + "temperature": true + }, + "deepseek/deepseek-v3.2-speciale": { + "id": "deepseek/deepseek-v3.2-speciale", + "family": "deepseek", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "input": 163000, + "output": 163840 + }, + "temperature": true + }, + "deepseek/deepseek-v3.2": { + "id": "deepseek/deepseek-v3.2", + "family": "deepseek", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163842, + "input": 163000, + "output": 8000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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-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-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 + } + }, + "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 + }, + "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 + } + }, + "arcee-ai/trinity-mini": { + "id": "arcee-ai/trinity-mini", + "family": "trinity", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 131072 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "deepcogito/cogito-v2.1-671b": { + "id": "deepcogito/cogito-v2.1-671b", + "family": "cogito", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "temperature": true + }, + "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 + } + }, + "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/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: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 } }, @@ -36941,25 +7539,6 @@ "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", @@ -36979,48 +7558,10 @@ "output": 8192 } }, - "nousresearch 2/hermes-4-405b:thinking": { - "id": "NousResearch 2/hermes-4-405b:thinking", - "family": "nousresearch", + "soob3123/veiled-calla-12b": { + "id": "soob3123/Veiled-Calla-12B", + "family": "llama", "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": [ @@ -37033,31 +7574,12 @@ "limit": { "context": 32768, "input": 32768, - "output": 65536 + "output": 8192 } }, - "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", + "soob3123/grayline-qwen3-8b": { + "id": "soob3123/GrayLine-Qwen3-8B", + "family": "qwen", "reasoning": false, "toolCall": false, "modalities": { @@ -37069,14 +7591,227 @@ ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 65536 + "context": 16384, + "input": 16384, + "output": 32768 } }, - "deepseek-ai/deepseek-v3.1-terminus:thinking": { - "id": "deepseek-ai/DeepSeek-V3.1-Terminus:thinking", - "family": "deepseek-thinking", + "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 + } + }, + "nex-agi/deepseek-v3.1-nex-n1": { + "id": "nex-agi/DeepSeek-V3.1-Nex-N1", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 128000, + "output": 131000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "anthracite-org/magnum-v4-72b": { + "id": "anthracite-org/magnum-v4-72b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "input": 16384, + "output": 2048 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "undi95/remm-slerp-l2-13b": { + "id": "undi95/remm-slerp-l2-13b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "input": 6144, + "output": 4096 + }, + "temperature": true + }, + "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 + } + }, + "allenai/molmo-2-8b": { + "id": "allenai/molmo-2-8b", + "family": "allenai", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 36864, + "input": 36864, + "output": 36864 + } + }, + "allenai/olmo-3.1-32b-instruct": { + "id": "allenai/olmo-3.1-32b-instruct", + "family": "allenai", "reasoning": false, "toolCall": true, "modalities": { @@ -37088,9 +7823,244 @@ ] }, "limit": { - "context": 128000, + "context": 65536, + "input": 65536, + "output": 32768 + }, + "temperature": true + }, + "allenai/olmo-3.1-32b-think": { + "id": "allenai/olmo-3.1-32b-think", + "family": "allenai", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65536, + "output": 8192 + } + }, + "allenai/olmo-3-32b-think": { + "id": "allenai/olmo-3-32b-think", + "family": "allenai", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, "input": 128000, "output": 65536 + }, + "temperature": true + }, + "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 + } + }, + "stepfun-ai/step-3.5-flash": { + "id": "stepfun-ai/Step-3.5-Flash", + "family": "step", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "input": 256000, + "output": 262000 + }, + "temperature": true + }, + "zai-org/glm-4.7": { + "id": "zai-org/GLM-4.7", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 200000, + "output": 8192 + }, + "temperature": true + }, + "zai-org/glm-5": { + "id": "zai-org/GLM-5", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "input": 200000, + "output": 205000 + }, + "temperature": true + }, + "zai-org/glm-5.1": { + "id": "zai-org/glm-5.1", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202000, + "input": 200000, + "output": 202000 + }, + "temperature": true + }, + "zai-org/glm-5.1:thinking": { + "id": "zai-org/glm-5.1:thinking", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 131072 + } + }, + "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 + } + }, + "zai-org/glm-4.7-flash": { + "id": "zai-org/GLM-4.7-Flash", + "family": "glm-flash", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "input": 200000, + "output": 16384 + }, + "temperature": true + }, + "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 + } + }, + "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 } }, "raifle/sorcererlm-8x22b": { @@ -37113,8 +8083,371 @@ "output": 8192 } }, - "mlabonne/neuraldaredevil-8b-abliterated": { - "id": "mlabonne/NeuralDaredevil-8B-abliterated", + "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 + } + }, + "mistralai/mistral-saba": { + "id": "mistralai/mistral-saba", + "family": "mistral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32000, + "output": 32768 + }, + "temperature": true + }, + "mistralai/mistral-large-3-675b-instruct-2512": { + "id": "mistralai/mistral-large-3-675b-instruct-2512", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "mistralai/devstral-2-123b-instruct-2512": { + "id": "mistralai/devstral-2-123b-instruct-2512", + "family": "devstral", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "mistralai/codestral-2508": { + "id": "mistralai/codestral-2508", + "family": "codestral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 51200 + }, + "temperature": true + }, + "mistralai/ministral-14b-instruct-2512": { + "id": "mistralai/ministral-14b-instruct-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 262144 + }, + "temperature": true + }, + "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/ministral-8b-2512": { + "id": "mistralai/ministral-8b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 32768 + }, + "temperature": true + }, + "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-medium-3.1": { + "id": "mistralai/mistral-medium-3.1", + "family": "mistral-medium", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 26215 + }, + "temperature": true + }, + "mistralai/ministral-3b-2512": { + "id": "mistralai/ministral-3b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "temperature": true + }, + "mistralai/mistral-nemo-instruct-2407": { + "id": "mistralai/Mistral-Nemo-Instruct-2407", + "family": "mistral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 16384, + "output": 65536 + }, + "temperature": true + }, + "mistralai/mistral-medium-3": { + "id": "mistralai/mistral-medium-3", + "family": "mistral-medium", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 26215 + }, + "temperature": true + }, + "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/devstral-small-2505": { + "id": "mistralai/Devstral-Small-2505", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 32768, + "output": 4096 + }, + "temperature": true + }, + "mistralai/mistral-small-creative": { + "id": "mistralai/mistral-small-creative", + "family": "mistral-small", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + } + }, + "mistralai/mistral-large": { + "id": "mistralai/mistral-large", + "family": "mistral-large", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 25600 + }, + "temperature": true + }, + "mistralai/ministral-14b-2512": { + "id": "mistralai/ministral-14b-2512", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 262144, + "output": 52429 + }, + "temperature": true + }, + "shisa-ai/shisa-v2.1-llama3.3-70b": { + "id": "shisa-ai/shisa-v2.1-llama3.3-70b", "family": "llama", "reasoning": false, "toolCall": false, @@ -37126,12 +8459,2423 @@ "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 + } + }, + "meta-llama/llama-3.3-70b-instruct": { + "id": "meta-llama/Llama-3.3-70B-Instruct", + "family": "llama", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 8192 + }, + "temperature": true + }, + "meta-llama/llama-4-scout": { + "id": "meta-llama/llama-4-scout", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 327680, + "input": 328000, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-4-maverick": { + "id": "meta-llama/llama-4-maverick", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048576, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-3.2-90b-vision-instruct": { + "id": "meta-llama/Llama-3.2-90B-Vision-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 131072, + "output": 4096 + }, + "temperature": true + }, + "meta-llama/llama-3.2-3b-instruct": { + "id": "meta-llama/llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 80000, + "input": 131072, + "output": 16384 + }, + "temperature": true + }, + "meta-llama/llama-3.1-8b-instruct": { + "id": "meta-llama/Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 8000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "gryphe/mythomax-l2-13b": { + "id": "gryphe/mythomax-l2-13b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "input": 4000, + "output": 4096 + }, + "temperature": true + }, + "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 + } + }, + "x-ai/grok-4-fast": { + "id": "x-ai/grok-4-fast", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 30000 + }, + "temperature": true + }, + "x-ai/grok-code-fast-1": { + "id": "x-ai/grok-code-fast-1", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 10000 + }, + "temperature": true + }, + "x-ai/grok-4.1-fast": { + "id": "x-ai/grok-4.1-fast", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "input": 2000000, + "output": 30000 + }, + "temperature": true + }, + "x-ai/grok-4.1-fast-reasoning": { + "id": "x-ai/grok-4.1-fast-reasoning", + "family": "grok", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 20000000, + "input": 2000000, + "output": 2000000 + }, + "temperature": true + }, + "tencent/hunyuan-mt-7b": { + "id": "tencent/Hunyuan-MT-7B", + "family": "hunyuan", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 8192, + "output": 33000 + }, + "temperature": true + }, + "microsoft/wizardlm-2-8x22b": { + "id": "microsoft/wizardlm-2-8x22b", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65535, + "input": 65536, + "output": 8000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "cohere/command-r-plus-08-2024": { + "id": "cohere/command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4000 + }, + "temperature": true + }, + "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 + }, + "nvidia/llama-3.1-nemotron-ultra-253b-v1": { + "id": "nvidia/llama-3.1-nemotron-ultra-253b-v1", + "family": "llama", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 8192 + }, + "temperature": true + }, + "nvidia/nemotron-3-nano-30b-a3b": { + "id": "nvidia/nemotron-3-nano-30b-a3b", + "family": "nemotron", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 262144 + }, + "temperature": true + }, + "nvidia/nvidia-nemotron-nano-9b-v2": { + "id": "nvidia/nvidia-nemotron-nano-9b-v2", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 128000, + "output": 131072 + }, + "temperature": true + }, + "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": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1", + "family": "nemotron", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "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 + } + }, + "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.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/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/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/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-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 + } + }, + "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-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 + } + }, + "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": { + "id": "deepseek-ai/DeepSeek-V3.1", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 128000, + "output": 164000 + }, + "temperature": true + }, + "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 + } + }, + "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.2-exp": { + "id": "deepseek-ai/DeepSeek-V3.2-Exp", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 163840, + "output": 164000 + }, + "temperature": true + }, + "deepseek-ai/deepseek-r1-0528": { + "id": "deepseek-ai/deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 120000, + "output": 4096 + }, + "temperature": true + }, + "deepseek-ai/deepseek-v3.1-terminus": { + "id": "deepseek-ai/DeepSeek-V3.1-Terminus", + "family": "deepseek", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 164000, + "input": 128000, + "output": 164000 + }, + "temperature": true + }, + "openai/gpt-5.1-codex-max": { + "id": "openai/gpt-5.1-codex-max", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5.2-chat": { + "id": "openai/gpt-5.2-chat", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-4o-mini-search-preview": { + "id": "openai/gpt-4o-mini-search-preview", + "family": "gpt-mini", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 111616, + "output": 16384 + }, + "temperature": true + }, + "openai/chatgpt-4o-latest": { + "id": "openai/chatgpt-4o-latest", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 8192 + }, + "temperature": false + }, + "openai/gpt-5.2-pro": { + "id": "openai/gpt-5.2-pro", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5-mini": { + "id": "openai/gpt-5-mini", + "family": "gpt-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5-nano": { + "id": "openai/gpt-5-nano", + "family": "gpt-nano", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-4-turbo": { + "id": "openai/gpt-4-turbo", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "openai/gpt-5.2": { + "id": "openai/gpt-5.2", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o3-mini-high": { + "id": "openai/o3-mini-high", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-4o-mini": { + "id": "openai/gpt-4o-mini", + "family": "gpt-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini-deep-research": { + "id": "openai/o4-mini-deep-research", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5.1-chat": { + "id": "openai/gpt-5.1-chat", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 400000, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini": { + "id": "openai/o4-mini", + "family": "o-mini", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5.2-codex": { + "id": "openai/gpt-5.2-codex", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-5.1-codex-mini": { + "id": "openai/gpt-5.1-codex-mini", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o1-preview": { + "id": "openai/o1-preview", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 32768 + }, + "temperature": false + }, + "openai/gpt-4o-2024-08-06": { + "id": "openai/gpt-4o-2024-08-06", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-5.1": { + "id": "openai/gpt-5.1", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/o1": { + "id": "openai/o1", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-3.5-turbo": { + "id": "openai/gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "input": 12289, + "output": 4096 + }, + "temperature": true + }, + "openai/o3-deep-research": { + "id": "openai/o3-deep-research", + "family": "o", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 100000, + "output": 100000 + }, + "temperature": false + }, + "openai/o3-mini": { + "id": "openai/o3-mini", + "family": "o-mini", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-4-turbo-preview": { + "id": "openai/gpt-4-turbo-preview", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 4096 + }, + "temperature": true + }, + "openai/o1-pro": { + "id": "openai/o1-pro", + "family": "o-pro", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-5-codex": { + "id": "openai/gpt-5-codex", + "family": "gpt-codex", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": false + }, + "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 + } + }, + "openai/gpt-4o-search-preview": { + "id": "openai/gpt-4o-search-preview", + "family": "gpt", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + } + }, + "openai/gpt-4.1-nano": { + "id": "openai/gpt-4.1-nano", + "family": "gpt-nano", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/o4-mini-high": { + "id": "openai/o4-mini-high", + "family": "o-mini", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + } + }, + "openai/o3": { + "id": "openai/o3", + "family": "o", + "reasoning": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 100000 + }, + "temperature": false + }, + "openai/gpt-oss-20b": { + "id": "openai/gpt-oss-20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 98304, + "output": 65536 + }, + "temperature": true + }, + "openai/gpt-5-pro": { + "id": "openai/gpt-5-pro", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "input": 128000, + "output": 272000 + }, + "temperature": true + }, + "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-4o": { + "id": "openai/gpt-4o", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "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/gpt-5": { + "id": "openai/gpt-5", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-oss-safeguard-20b": { + "id": "openai/gpt-oss-safeguard-20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 65536, + "output": 65536 + }, + "temperature": true + }, + "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-oss-120b": { + "id": "openai/gpt-oss-120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 124000, + "output": 131072 + }, + "temperature": true + }, + "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/gpt-4.1": { + "id": "openai/gpt-4.1", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-4.1-mini": { + "id": "openai/gpt-4.1-mini", + "family": "gpt-mini", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 1047576, + "output": 16384 + }, + "temperature": true + }, + "openai/gpt-5.1-codex": { + "id": "openai/gpt-5.1-codex", + "family": "gpt", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "input": 272000, + "output": 128000 + }, + "temperature": true + }, + "openai/gpt-4o-2024-11-20": { + "id": "openai/gpt-4o-2024-11-20", + "family": "gpt", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 16384 + }, + "temperature": true + }, + "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 + } + }, + "amazon/nova-lite-v1": { + "id": "amazon/nova-lite-v1", + "family": "nova-lite", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "input": 300000, + "output": 5120 + }, + "temperature": true + }, + "amazon/nova-pro-v1": { + "id": "amazon/nova-pro-v1", + "family": "nova-pro", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 300000, + "input": 300000, + "output": 5120 + }, + "temperature": true + }, + "amazon/nova-2-lite-v1": { + "id": "amazon/nova-2-lite-v1", + "family": "nova", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 65535 + }, + "temperature": true + }, + "amazon/nova-micro-v1": { + "id": "amazon/nova-micro-v1", + "family": "nova-micro", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 128000, + "output": 5120 + }, + "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 + } + }, + "sao10k/l3.1-70b-hanami-x1": { + "id": "sao10k/l3.1-70b-hanami-x1", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "input": 16384, + "output": 16000 + }, + "temperature": true + }, + "sao10k/l3-8b-stheno-v3.2": { + "id": "sao10k/L3-8B-Stheno-v3.2", + "family": "llama", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "input": 16384, + "output": 32000 + }, + "temperature": true + }, + "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 + } + }, + "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": { + "id": "z-ai/glm-4.5v", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 64000, + "output": 16384 + }, + "temperature": true + }, + "z-ai/glm-4.6": { + "id": "z-ai/glm-4.6", + "family": "glm", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 200000, + "output": 204800 + }, + "temperature": true + }, + "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 + } + }, + "baidu/ernie-4.5-vl-28b-a3b": { + "id": "baidu/ernie-4.5-vl-28b-a3b", + "family": "ernie", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 30000, + "input": 32768, + "output": 8000 + }, + "temperature": true + }, + "baidu/ernie-4.5-300b-a47b": { + "id": "baidu/ERNIE-4.5-300B-A47B", + "family": "ernie", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 131072, + "output": 131000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 } }, + "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-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 + } + }, + "minimax/minimax-m2.7": { + "id": "minimax/minimax-m2.7", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 204800, + "output": 131000 + }, + "temperature": true + }, + "minimax/minimax-01": { + "id": "minimax/minimax-01", + "family": "minimax", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000192, + "input": 1000192, + "output": 1000192 + }, + "temperature": true + }, + "minimax/minimax-m2.1": { + "id": "minimax/minimax-m2.1", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "input": 200000, + "output": 131072 + }, + "temperature": true + }, + "minimax/minimax-m2-her": { + "id": "minimax/minimax-m2-her", + "family": "minimax", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "input": 65532, + "output": 2048 + }, + "temperature": true + }, + "minimax/minimax-m2.5": { + "id": "minimax/minimax-m2.5", + "family": "minimax-m2.5", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 204800, + "output": 131072 + }, + "temperature": true + }, + "qwen/qwen3.5-397b-a17b": { + "id": "Qwen/Qwen3.5-397B-A17B", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 258048, + "output": 130000 + }, + "temperature": true + }, "unsloth/gemma-3-1b-it": { "id": "unsloth/gemma-3-1b-it", "family": "unsloth", @@ -37214,201 +10958,132 @@ }, "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", + "thudm/glm-z1-9b-0414": { + "id": "THUDM/GLM-Z1-9B-0414", + "family": "glm-z", "reasoning": true, "toolCall": true, "modalities": { "input": [ - "text", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 163000, - "input": 163000, + "context": 131000, + "input": 32000, + "output": 131000 + }, + "temperature": true + }, + "thudm/glm-4-9b-0414": { + "id": "THUDM/GLM-4-9B-0414", + "family": "glm", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 32000, + "output": 33000 + }, + "temperature": true + }, + "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 } }, - "marinaraspaghetti/nemomix-unleashed-12b": { - "id": "MarinaraSpaghetti/NemoMix-Unleashed-12B", - "family": "mistral-nemo", + "thudm/glm-4-32b-0414": { + "id": "THUDM/GLM-4-32B-0414", + "family": "glm", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "input": 128000, + "output": 33000 + }, + "temperature": true + }, + "thudm/glm-z1-32b-0414": { + "id": "THUDM/GLM-Z1-32B-0414", + "family": "glm-z", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "input": 128000, + "output": 131000 + }, + "temperature": true + }, + "google/gemini-3-flash-preview": { + "id": "google/gemini-3-flash-preview", + "family": "gemini-flash", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "input": 1048756, + "output": 65536 + }, + "temperature": true + }, + "google/gemini-flash-1.5": { + "id": "google/gemini-flash-1.5", + "family": "gemini-flash", "reasoning": false, "toolCall": false, "modalities": { @@ -37420,16 +11095,16 @@ ] }, "limit": { - "context": 32768, - "input": 32768, + "context": 2000000, + "input": 2000000, "output": 8192 } }, - "moonshotai/kimi-k2.5:thinking": { - "id": "moonshotai/kimi-k2.5:thinking", - "family": "kimi-thinking", + "google/gemini-3-flash-preview-thinking": { + "id": "google/gemini-3-flash-preview-thinking", + "family": "gemini-flash", "reasoning": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text", @@ -37440,13 +11115,55 @@ ] }, "limit": { - "context": 256000, - "input": 256000, + "context": 1048756, + "input": 1048756, "output": 65536 } }, - "moonshotai/kimi-k2-thinking-turbo-original": { - "id": "moonshotai/kimi-k2-thinking-turbo-original", + "moonshotai/kimi-k2.5": { + "id": "moonshotai/kimi-k2.5", + "family": "kimi", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 262144 + }, + "temperature": false + }, + "moonshotai/kimi-k2-instruct": { + "id": "moonshotai/kimi-k2-instruct", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 190000, + "output": 16384 + }, + "temperature": true + }, + "moonshotai/kimi-k2-thinking-original": { + "id": "moonshotai/kimi-k2-thinking-original", "family": "kimi-thinking", "reasoning": true, "toolCall": false, @@ -37503,8 +11220,8 @@ "output": 131072 } }, - "moonshotai/kimi-k2-thinking-original": { - "id": "moonshotai/kimi-k2-thinking-original", + "moonshotai/kimi-k2-thinking-turbo-original": { + "id": "moonshotai/kimi-k2-thinking-turbo-original", "family": "kimi-thinking", "reasoning": true, "toolCall": false, @@ -37522,11 +11239,11 @@ "output": 16384 } }, - "google/gemini-flash-1.5": { - "id": "google/gemini-flash-1.5", - "family": "gemini-flash", + "moonshotai/kimi-k2-instruct-0905": { + "id": "moonshotai/kimi-k2-instruct-0905", + "family": "kimi", "reasoning": false, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text" @@ -37536,34 +11253,15 @@ ] }, "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" - ] + "context": 262144, + "input": 256000, + "output": 16384 }, - "limit": { - "context": 1048756, - "input": 1048756, - "output": 65536 - } + "temperature": true }, - "z-ai/glm-4.6:thinking": { - "id": "z-ai/glm-4.6:thinking", - "family": "glm", + "moonshotai/kimi-k2-thinking": { + "id": "moonshotai/kimi-k2-thinking", + "family": "kimi-thinking", "reasoning": true, "toolCall": true, "modalities": { @@ -37575,16 +11273,17 @@ ] }, "limit": { - "context": 200000, - "input": 200000, - "output": 65535 - } + "context": 216144, + "input": 120000, + "output": 216144 + }, + "temperature": true }, - "z-ai/glm-4.5v:thinking": { - "id": "z-ai/glm-4.5v:thinking", - "family": "glmv", + "moonshotai/kimi-k2.5:thinking": { + "id": "moonshotai/kimi-k2.5:thinking", + "family": "kimi-thinking", "reasoning": true, - "toolCall": false, + "toolCall": true, "modalities": { "input": [ "text", @@ -37594,33 +11293,14 @@ "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 + "output": 65536 } }, - "deepcogito/cogito-v1-preview-qwen-32b": { - "id": "deepcogito/cogito-v1-preview-qwen-32B", + "tongyi-zhiwen/qwenlong-l1-32b": { + "id": "Tongyi-Zhiwen/QwenLong-L1-32B", "family": "qwen", "reasoning": false, "toolCall": false, @@ -37635,26 +11315,7 @@ "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 + "output": 40960 } }, "nothingiisreal/l3.1-70b-celeste-v0.1-bf16": { @@ -37676,35 +11337,452 @@ "output": 16384 } }, - "x-ai/grok-4-fast:thinking": { - "id": "x-ai/grok-4-fast:thinking", - "family": "grok", + "aion-labs/aion-1.0": { + "id": "aion-labs/aion-1.0", + "family": "llama", "reasoning": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text", - "image" + "text" ], "output": [ "text" ] }, "limit": { - "context": 2000000, - "input": 2000000, - "output": 131072 - } + "context": 131072, + "input": 65536, + "output": 32768 + }, + "temperature": true }, - "x-ai/grok-4-07-09": { - "id": "x-ai/grok-4-07-09", - "family": "grok", + "aion-labs/aion-rp-llama-3.1-8b": { + "id": "aion-labs/aion-rp-llama-3.1-8b", + "family": "llama", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "input": 32768, + "output": 32768 + }, + "temperature": true + }, + "aion-labs/aion-1.0-mini": { + "id": "aion-labs/aion-1.0-mini", + "family": "deepseek", "reasoning": true, "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "input": 131072, + "output": 32768 + }, + "temperature": true + }, + "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 + } + }, + "minimaxai/minimax-m1-80k": { + "id": "minimaxai/minimax-m1-80k", + "family": "minimax", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 40000 + }, + "temperature": true + }, + "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" + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + } + }, + "anthropic/claude-opus-4.6": { + "id": "anthropic/claude-opus-4.6", + "family": "claude-opus", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "temperature": true + }, + "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: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 + } + }, + "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-sonnet-4.6": { + "id": "anthropic/claude-sonnet-4.6", + "family": "claude-sonnet", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "input": 1000000, + "output": 128000 + }, + "temperature": true + }, + "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 + } + }, + "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 + } + }, + "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-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.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 + } + }, + "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/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/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/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/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 + } + }, + "xiaomi/mimo-v2-flash-thinking-original": { + "id": "xiaomi/mimo-v2-flash-thinking-original", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" ], "output": [ "text" @@ -37713,7 +11791,65 @@ "limit": { "context": 256000, "input": 256000, - "output": 131072 + "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": { + "id": "xiaomi/mimo-v2-flash", + "family": "mimo", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 256000, + "output": 32000 + }, + "temperature": true + }, + "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 } }, "tngtech/deepseek-tng-r1t2-chimera": { @@ -37755,105 +11891,9 @@ "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", + "inflatebot/mn-12b-mag-mell-r1": { + "id": "inflatebot/MN-12B-Mag-Mell-R1", + "family": "mistral-nemo", "reasoning": false, "toolCall": false, "modalities": { @@ -37867,11 +11907,11 @@ "limit": { "context": 16384, "input": 16384, - "output": 16384 + "output": 8192 } }, - "readyart/ms3.2-the-omega-directive-24b-unslop-v2.0": { - "id": "ReadyArt/MS3.2-The-Omega-Directive-24B-Unslop-v2.0", + "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, @@ -37884,35 +11924,17 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 32768 + "context": 8192, + "input": 8192, + "output": 8192 } }, - "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", + "gpt-5.1-codex-max": { + "id": "gpt-5.1-codex-max", + "family": "gpt-codex", "reasoning": true, - "toolCall": false, + "temperature": false, + "toolCall": true, "modalities": { "input": [ "text", @@ -37924,589 +11946,59 @@ }, "limit": { "context": 400000, - "input": 400000, + "input": 272000, "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", + "kimi-k2.5": { + "id": "kimi-k2.5", "family": "kimi", - "reasoning": false, - "toolCall": false, + "reasoning": true, + "temperature": false, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image", + "video" ], "output": [ "text" ] }, "limit": { - "context": 128000, - "input": 128000, - "output": 131072 + "context": 262144, + "output": 262144 } }, - "galrionsoftworks/mn-loosecannon-12b-v1": { - "id": "GalrionSoftworks/MN-LooseCannon-12B-v1", - "family": "mistral-nemo", - "reasoning": false, - "toolCall": false, + "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" + "text", + "image", + "video", + "audio", + "pdf" ], "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, + "context": 1048576, "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", + "claude-sonnet-4-6": { + "id": "claude-sonnet-4-6", "family": "claude-sonnet", "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ @@ -38520,19 +12012,21 @@ }, "limit": { "context": 1000000, - "input": 1000000, - "output": 128000 + "output": 64000 } }, - "anthropic/claude-opus-4.6:thinking:low": { - "id": "anthropic/claude-opus-4.6:thinking:low", - "family": "claude-opus", + "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": [ @@ -38540,57 +12034,178 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 1048576, + "output": 65536, + "input": 128000 } }, - "anthropic/claude-opus-4.6:thinking": { - "id": "anthropic/claude-opus-4.6:thinking", - "family": "claude-opus", + "gpt-5.3-chat-latest": { + "id": "gpt-5.3-chat-latest", + "family": "gpt", "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 128000, + "output": 16384 } }, - "anthropic/claude-opus-4.6:thinking:medium": { - "id": "anthropic/claude-opus-4.6:thinking:medium", - "family": "claude-opus", + "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": 32768 + } + }, + "gpt-5-nano": { + "id": "gpt-5-nano", + "family": "gpt-nano", "reasoning": true, + "temperature": false, "toolCall": true, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, - "input": 1000000, - "output": 128000 + "context": 272000, + "output": 128000, + "input": 272000 } }, - "anthropic/claude-opus-4.6:thinking:max": { - "id": "anthropic/claude-opus-4.6:thinking:max", - "family": "claude-opus", + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "gpt-5.3-codex-xhigh": { + "id": "gpt-5.3-codex-xhigh", + "family": "gpt", + "reasoning": true, + "temperature": false, "toolCall": true, "modalities": { "input": [ @@ -38603,16 +12218,157 @@ ] }, "limit": { - "context": 1000000, - "input": 1000000, + "context": 400000, + "input": 272000, "output": 128000 } }, - "miromind-ai/mirothinker-v1.5-235b": { - "id": "miromind-ai/MiroThinker-v1.5-235B", + "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 + } + }, + "o3-mini": { + "id": "o3-mini", + "family": "o-mini", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "grok-4-0709": { + "id": "grok-4-0709", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "route-llm": { + "id": "route-llm", "family": "gpt", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "kimi-k2-turbo-preview": { + "id": "kimi-k2-turbo-preview", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38623,54 +12379,100 @@ }, "limit": { "context": 262144, - "input": 32768, - "output": 8192 - }, - "temperature": true + "output": 262144 + } }, - "sao10k/l3.3-70b-euryale-v2.3": { - "id": "Sao10K/L3.3-70B-Euryale-v2.3", - "family": "llama", - "reasoning": false, - "toolCall": false, + "claude-opus-4-6": { + "id": "claude-opus-4-6", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 20480, - "input": 20480, - "output": 16384 + "context": 1000000, + "output": 128000 } }, - "sao10k/l3.1-70b-euryale-v2.2": { - "id": "Sao10K/L3.1-70B-Euryale-v2.2", - "family": "llama", - "reasoning": false, - "toolCall": false, + "o3": { + "id": "o3", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 20480, - "input": 20480, + "context": 200000, + "output": 100000 + } + }, + "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 + } + }, + "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 } }, - "huihui-ai/deepseek-r1-distill-llama-70b-abliterated": { - "id": "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated", + "deepseek/deepseek-v3.1": { + "id": "deepseek/deepseek-v3.1", "family": "deepseek", "reasoning": true, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38680,35 +12482,16 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 163840, + "output": 128000 } }, - "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", + "qwen/qwq-32b": { + "id": "Qwen/QwQ-32B", "family": "qwen", "reasoning": true, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38718,16 +12501,16 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 131000, + "output": 131000 } }, - "huihui-ai/llama-3.3-70b-instruct-abliterated": { - "id": "huihui-ai/Llama-3.3-70B-Instruct-abliterated", - "family": "llama", + "qwen/qwen3-235b-a22b-instruct-2507": { + "id": "Qwen/Qwen3-235B-A22B-Instruct-2507", + "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38737,15 +12520,250 @@ ] }, "limit": { - "context": 16384, - "input": 16384, + "context": 262144, + "output": 131072 + } + }, + "qwen/qwen3-32b": { + "id": "qwen/qwen3-32b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 40960, + "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": 262000, + "output": 262000 + } + }, + "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": 33000, + "output": 4000 + } + }, + "zai-org/glm-4.5": { + "id": "zai-org/GLM-4.5", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000, + "input": 124000 + } + }, + "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": 205000, + "output": 205000 + } + }, + "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 + } + }, + "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": 16384 } }, - "huihui-ai/llama-3.1-nemotron-70b-instruct-hf-abliterated": { - "id": "huihui-ai/Llama-3.1-Nemotron-70B-Instruct-HF-abliterated", + "meta-llama/meta-llama-3.1-8b-instruct": { + "id": "meta-llama/Meta-Llama-3.1-8B-Instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000, + "input": 120000 + } + }, + "deepseek-ai/deepseek-r1": { + "id": "deepseek-ai/DeepSeek-R1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163839, + "output": 163839 + } + }, + "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": 164000, + "output": 164000, + "input": 160000 + } + }, + "perplexity/sonar": { + "id": "perplexity/sonar", + "family": "sonar", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + } + }, + "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 + } + }, + "nvidia/nemotron-3-super-120b-a12b": { + "id": "nvidia/nemotron-3-super-120b-a12b", "family": "nemotron", "reasoning": false, + "temperature": true, "toolCall": false, "modalities": { "input": [ @@ -38756,16 +12774,206 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 16384 + "context": 256000, + "output": 32000, + "input": 256000 } }, - "dmind/dmind-1-mini": { - "id": "dmind/dmind-1-mini", + "openai/gpt-5.4": { + "id": "openai/gpt-5.4", "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 128000 + } + }, + "google/gemini-3.1-pro-preview": { + "id": "google/gemini-3.1-pro-preview", + "family": "gemini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "google/gemini-2.5-pro": { + "id": "google/gemini-2.5-pro", + "family": "gemini-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-flash": { + "id": "google/gemini-2.5-flash", + "family": "gemini-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "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-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-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-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-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 + } + }, + "kwaipilot/kat-dev": { + "id": "Kwaipilot/KAT-Dev", + "family": "kat-coder", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38775,16 +12983,16 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 8192 + "context": 128000, + "output": 128000 } }, - "dmind/dmind-1": { - "id": "dmind/dmind-1", - "family": "gpt", - "reasoning": false, - "toolCall": false, + "qwen/qwen3.5-35b-a3b": { + "id": "qwen/qwen3.5-35b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38794,73 +13002,154 @@ ] }, "limit": { - "context": 32768, - "input": 32768, - "output": 8192 + "context": 262144, + "output": 262144 } }, - "eva-unit-01/eva-qwen2.5-72b-v0.2": { - "id": "EVA-UNIT-01/EVA-Qwen2.5-72B-v0.2", + "qwen/qwen3.5-122b-a10b": { + "id": "qwen/qwen3.5-122b-a10b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3.5-9b": { + "id": "qwen/qwen3.5-9b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "qwen/qwen3.5-27b": { + "id": "qwen/qwen3.5-27b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "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-vl-8b-instruct": { + "id": "Qwen/Qwen3-VL-8B-Instruct", "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 262000, + "output": 262000 } }, - "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", + "qwen/qwen3-vl-32b-instruct": { + "id": "Qwen/Qwen3-VL-32B-Instruct", "family": "qwen", "reasoning": false, - "toolCall": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen3-vl-30b-a3b-thinking": { + "id": "Qwen/Qwen3-VL-30B-A3B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-14b-instruct": { + "id": "Qwen/Qwen2.5-14B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text" @@ -38870,13 +13159,131 @@ ] }, "limit": { - "context": 16384, - "input": 16384, - "output": 8192 + "context": 33000, + "output": 4000 } }, - "qwen-3-235b-a22b-instruct-2507": { - "id": "qwen-3-235b-a22b-instruct-2507", + "qwen/qwen3-vl-235b-a22b-instruct": { + "id": "Qwen/Qwen3-VL-235B-A22B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "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": 262000, + "output": 262000, + "input": 120000 + } + }, + "qwen/qwen2.5-vl-32b-instruct": { + "id": "Qwen/Qwen2.5-VL-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "qwen/qwen3-omni-30b-a3b-thinking": { + "id": "Qwen/Qwen3-Omni-30B-A3B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "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": 131072 + } + }, + "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/qwen2.5-72b-instruct-128k": { + "id": "Qwen/Qwen2.5-72B-Instruct-128K", "family": "qwen", "reasoning": false, "temperature": true, @@ -38891,9 +13298,18207 @@ }, "limit": { "context": 131000, + "output": 4000 + } + }, + "qwen/qwen3-14b": { + "id": "Qwen/Qwen3-14B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "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/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": 262144, + "output": 65536, + "input": 120000 + } + }, + "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": 16384, + "input": 120000 + } + }, + "qwen/qwen3-8b": { + "id": "Qwen/Qwen3-8B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "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": 262000, + "output": 262000 + } + }, + "qwen/qwen3-vl-8b-thinking": { + "id": "Qwen/Qwen3-VL-8B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "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-30b-a3b-instruct": { + "id": "Qwen/Qwen3-VL-30B-A3B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "qwen/qwen2.5-coder-32b-instruct": { + "id": "Qwen/Qwen2.5-Coder-32B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen2.5-7b-instruct": { + "id": "Qwen/Qwen2.5-7B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 33000, + "output": 4000 + } + }, + "qwen/qwen3-vl-235b-a22b-thinking": { + "id": "Qwen/Qwen3-VL-235B-A22B-Thinking", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "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": 262144, + "output": 32768, + "input": 120000 + } + }, + "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/qwen2.5-vl-72b-instruct": { + "id": "Qwen/Qwen2.5-VL-72B-Instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 4000, + "input": 120000 + } + }, + "zai-org/glm-4.5v": { + "id": "zai-org/GLM-4.5V", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 66000, + "output": 66000 + } + }, + "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": 131000, + "output": 131000 + } + }, + "zai-org/glm-4.5-air": { + "id": "zai-org/GLM-4.5-Air", + "family": "glm-air", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000, + "input": 124000 + } + }, + "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/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 + } + }, + "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 + } + }, + "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 + } + }, + "tencent/hunyuan-a13b-instruct": { + "id": "tencent/Hunyuan-A13B-Instruct", + "family": "hunyuan", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "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.1": { + "id": "Pro/zai-org/GLM-5.1", + "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/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-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.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-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 + } + }, + "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/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 + } + }, + "paddlepaddle/paddleocr-vl": { + "id": "paddlepaddle/paddleocr-vl", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-v3": { + "id": "deepseek-ai/DeepSeek-V3", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "deepseek-ai/deepseek-v3-0324": { + "id": "deepseek-ai/DeepSeek-V3-0324", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840, + "input": 120000 + } + }, + "minimax-m2.5": { + "id": "MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072, + "input": 196601 + } + }, + "minimax-m2.7": { + "id": "MiniMax-M2.7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-r1": { + "id": "deepseek/deepseek-r1", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 8192 + } + }, + "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-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 + } + }, + "deepseek/deepseek-v3.1-terminus": { + "id": "deepseek/deepseek-v3.1-terminus", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "openrouter/elephant-alpha": { + "id": "openrouter/elephant-alpha", + "family": "elephant", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "openrouter/free": { + "id": "openrouter/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "input": 200000, + "output": 32768 + } + }, + "arcee-ai/trinity-large-thinking": { + "id": "arcee-ai/trinity-large-thinking", + "family": "trinity", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262100, + "output": 80000 + } + }, + "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": 131072, + "output": 131072 + } + }, + "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 + } + }, + "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-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-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-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-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 + } + }, + "nousresearch/hermes-4-405b": { + "id": "NousResearch/Hermes-4-405B", + "family": "hermes", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 120000 + } + }, + "nousresearch/hermes-4-70b": { + "id": "NousResearch/Hermes-4-70B", + "family": "nousresearch", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192, + "input": 120000 + } + }, + "stepfun/step-3.5-flash": { + "id": "stepfun/step-3.5-flash", + "family": "step", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 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-2603": { + "id": "mistralai/mistral-small-2603", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "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-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/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 + } + }, + "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 + } + }, + "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 + } + }, + "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": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "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 + } + }, + "x-ai/grok-4": { + "id": "x-ai/grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "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-beta": { + "id": "x-ai/grok-4.20-beta", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "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": { + "id": "x-ai/grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "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-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: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-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 + } + }, + "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": 131072 + } + }, + "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 + } + }, + "inception/mercury-edit-2": { + "id": "inception/mercury-edit-2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "inception/mercury-2": { + "id": "inception/mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "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-chat": { + "id": "openai/gpt-5-chat", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + } + }, + "openai/gpt-5.3-codex": { + "id": "openai/gpt-5.3-codex", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "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-5.4-mini": { + "id": "openai/gpt-5.4-mini", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "openai/gpt-5.4-nano": { + "id": "openai/gpt-5.4-nano", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "openai/gpt-5-image": { + "id": "openai/gpt-5-image", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "openai/gpt-5.4-pro": { + "id": "openai/gpt-5.4-pro", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1050000, + "input": 922000, + "output": 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 + } + }, + "z-ai/glm-4.7": { + "id": "z-ai/glm-4.7", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 65535 + } + }, + "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-5": { + "id": "z-ai/glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "z-ai/glm-5.1": { + "id": "z-ai/glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "z-ai/glm-4.5": { + "id": "z-ai/glm-4.5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "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.5-air": { + "id": "z-ai/glm-4.5-air", + "family": "glm-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + } + }, + "z-ai/glm-5-turbo": { + "id": "z-ai/glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "minimax/minimax-m2": { + "id": "minimax/minimax-m2", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262114, + "output": 262114 + } + }, + "minimax/minimax-m2.5:free": { + "id": "minimax/minimax-m2.5:free", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "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 + } + }, + "qwen/qwen3.5-flash-02-23": { + "id": "qwen/qwen3.5-flash-02-23", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3.6-plus": { + "id": "qwen/qwen3.6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65536 + } + }, + "qwen/qwen3-max": { + "id": "qwen/qwen3-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "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/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/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-coder": { + "id": "qwen/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "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 + } + }, + "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/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/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/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": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "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-3n-e4b-it": { + "id": "google/gemma-3n-e4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "google/gemini-3.1-flash-lite-preview": { + "id": "google/gemini-3.1-flash-lite-preview", + "family": "gemini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 65000 + } + }, + "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-3-pro-preview": { + "id": "google/gemini-3-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 + } + }, + "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/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-4-31b-it": { + "id": "google/gemma-4-31B-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "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-3-12b-it": { + "id": "google/gemma-3-12b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "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 + } + }, + "google/gemma-4-31b-it:free": { + "id": "google/gemma-4-31b-it:free", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "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-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/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/gemma-3-27b-it": { + "id": "google/gemma-3-27b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 37000, + "output": 8192, + "input": 100000 + } + }, + "google/gemma-4-26b-a4b-it": { + "id": "google/gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "google/gemma-4-26b-a4b-it:free": { + "id": "google/gemma-4-26b-a4b-it:free", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "google/gemini-2.5-flash-lite": { + "id": "google/gemini-2.5-flash-lite", + "family": "gemini-flash-lite", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "audio", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "moonshotai/kimi-k2-0905": { + "id": "moonshotai/kimi-k2-0905", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "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": { + "id": "moonshotai/kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "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.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 + } + }, + "anthropic/claude-opus-4.7": { + "id": "anthropic/claude-opus-4.7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-sonnet-4": { + "id": "anthropic/claude-sonnet-4", + "family": "claude-sonnet", + "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": 200000, + "output": 64000 + } + }, + "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-opus-4": { + "id": "anthropic/claude-opus-4", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "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-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": 64000 + } + }, + "xiaomi/mimo-v2-omni": { + "id": "xiaomi/mimo-v2-omni", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "audio", + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "xiaomi/mimo-v2-pro": { + "id": "xiaomi/mimo-v2-pro", + "family": "mimo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "accounts/fireworks/models/glm-5p1": { + "id": "accounts/fireworks/models/glm-5p1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202800, + "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/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/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/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/qwen3p6-plus": { + "id": "accounts/fireworks/models/qwen3p6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "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/minimax-m2p7": { + "id": "accounts/fireworks/models/minimax-m2p7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 196608 + } + }, + "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-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/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/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 + } + }, + "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-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/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 + } + }, + "k2p5": { + "id": "k2p5", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "glm-5": { + "id": "glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "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 + } + }, + "glm-5.1": { + "id": "glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "deepseek-v3": { + "id": "deepseek-v3", + "family": "deepseek", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "deepseek-r1-0528": { + "id": "deepseek-r1-0528", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "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 + } + }, + "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-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.2": { + "id": "siliconflow/deepseek-v3.2", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "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.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 + } + }, + "gpt-5.2-pro": { + "id": "gpt-5.2-pro", + "family": "gpt", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 272000, + "input": 272000 + } + }, + "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, + "output": 128000, + "input": 272000 + } + }, + "gpt-5-chat-latest": { + "id": "gpt-5-chat-latest", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000, + "input": 272000 + } + }, + "deepseek/deepseek-v3-0324": { + "id": "deepseek/deepseek-v3-0324", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "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": 65536, + "output": 8192 + } + }, + "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 + } + }, + "baidu/ernie-4.5-vl-424b-a47b": { + "id": "baidu/ernie-4.5-vl-424b-a47b", + "family": "ernie", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 16000 + } + }, + "baidu/ernie-4.5-300b-a47b-paddle": { + "id": "baidu/ernie-4.5-300b-a47b-paddle", + "family": "ernie", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 123000, + "output": 12000 + } + }, + "qwen/qwen3-32b-fp8": { + "id": "qwen/qwen3-32b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "qwen/qwen3-30b-a3b-fp8": { + "id": "qwen/qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "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-235b-a22b-fp8": { + "id": "qwen/qwen3-235b-a22b-fp8", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "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 + } + }, + "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 + } + }, + "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": 262000, + "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": 262144 + } + }, + "qwen3-235b": { + "id": "qwen3-235b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "kimi-k2": { + "id": "kimi-k2", + "family": "kimi", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "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 + } + }, + "qwen/qwen3-embedding-8b": { + "id": "Qwen/Qwen3-Embedding-8B", + "family": "text-embedding", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960, + "input": 32768 + } + }, + "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 + } + }, + "minimaxai/minimax-m2.5": { + "id": "MiniMaxAI/MiniMax-M2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "minimaxai/minimax-m2.7": { + "id": "MiniMaxAI/MiniMax-M2.7", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "minimaxai/minimax-m2.1": { + "id": "MiniMaxAI/MiniMax-M2.1", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 197000, + "output": 131000, + "input": 120000 + } + }, + "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": 163840 + }, + "family": "deepseek" + }, + "inclusionai/ring-1t": { + "id": "inclusionai/ring-1t", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "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 + } + }, + "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": { + "id": "stepfun/step-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 64000 + } + }, + "kuaishou/kat-coder-pro-v2": { + "id": "kuaishou/kat-coder-pro-v2", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 80000 + } + }, + "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.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-chat": { + "id": "openai/gpt-5.3-chat", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384, + "input": 111616 + }, + "family": "gpt" + }, + "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-5v-turbo": { + "id": "z-ai/glm-5v-turbo", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 131072 + } + }, + "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.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.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-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 + } + }, + "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 + } + }, + "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-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-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-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 + } + }, + "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 + } + }, + "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.5-lightning": { + "id": "minimax/minimax-m2.5-lightning", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "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 + } + }, + "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" + }, + "sapiens-ai/agnes-1.5-lite": { + "id": "sapiens-ai/agnes-1.5-lite", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "sapiens-ai/agnes-1.5-pro": { + "id": "sapiens-ai/agnes-1.5-pro", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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" + }, + "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 + } + }, + "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-ocr": { + "id": "deepseek/deepseek-ocr", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "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-v3-turbo": { + "id": "deepseek/deepseek-v3-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 64000, + "output": 16000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "meta-llama/llama-4-scout-17b-16e-instruct": { + "id": "meta-llama/llama-4-scout-17b-16e-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + }, + "family": "llama" + }, + "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 + } + }, + "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 + } + }, + "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-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/l3-8b-lunaris": { + "id": "sao10k/l3-8b-lunaris", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "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-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 + } + }, + "minimax/minimax-m2.5-highspeed": { + "id": "minimax/minimax-m2.5-highspeed", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 0, + "output": 0 + } + }, + "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/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-8b-fp8": { + "id": "qwen/qwen3-8b-fp8", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "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 + } + }, + "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 + } + }, + "mimo-v2-tts": { + "id": "mimo-v2-tts", + "family": "mimo", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 8000, + "output": 16000 + } + }, + "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 + } + }, + "meta-llama/llama-3.1-70b-instruct": { + "id": "meta-llama/llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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/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 + } + }, + "qwen/qwen3-30b-a3b": { + "id": "qwen/qwen3-30b-a3b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen3-235b-a22b": { + "id": "Qwen/Qwen3-235B-A22B", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131000, + "output": 131000 + } + }, + "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 + } + }, + "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/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 + } + }, + "zai-org/glm-5.1-tee": { + "id": "zai-org/GLM-5.1-TEE", + "family": "glm", + "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-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.7-fp8": { + "id": "zai-org/GLM-4.7-FP8", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096, + "input": 124000 + } + }, + "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.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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-r1-distill-llama-70b": { + "id": "deepseek-ai/deepseek-r1-distill-llama-70b", + "family": "deepseek-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "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-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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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/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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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/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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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.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 + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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" + }, + "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 + } + }, + "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 + } + }, + "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" + }, + "qwen3-vl-30b-a3b-thinking": { + "id": "qwen3-vl-30b-a3b-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "qwen" + }, + "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 + } + }, + "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" + }, + "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 + } + }, + "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" + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-30b-a3b-thinking-2507": { + "id": "qwen3-30b-a3b-thinking-2507", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + }, + "family": "qwen" + }, + "glm-4.5-air": { + "id": "glm-4.5-air", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 98304 + }, + "family": "glm-air" + }, + "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" + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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-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-20b": { + "id": "gpt-oss-20b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32766 + }, + "family": "gpt-oss" + }, + "mimo-v2-flash": { + "id": "mimo-v2-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + }, + "family": "mimo" + }, + "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 + } + }, + "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" + }, + "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 + } + }, + "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 + } + }, + "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-thinking": { + "id": "deepseek/deepseek-v3.1-terminus-thinking", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32000 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "meituan/longcat-flash-chat": { + "id": "meituan/longcat-flash-chat", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + }, + "family": "longcat" + }, + "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 + } + }, + "rekaai/reka-edge": { + "id": "rekaai/reka-edge", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16384, + "output": 16384 + } + }, + "rekaai/reka-flash-3": { + "id": "rekaai/reka-flash-3", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "writer/palmyra-x5": { + "id": "writer/palmyra-x5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1040000, + "output": 8192 + } + }, + "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 + } + }, + "perplexity/sonar-pro": { + "id": "perplexity/sonar-pro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8000 + }, + "family": "sonar-pro" + }, + "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 + } + }, + "perplexity/sonar-reasoning-pro": { + "id": "perplexity/sonar-reasoning-pro", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 8000 + }, + "family": "sonar-reasoning" + }, + "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 + } + }, + "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/bodybuilder": { + "id": "openrouter/bodybuilder", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "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/spotlight": { + "id": "arcee-ai/spotlight", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65537 + } + }, + "arcee-ai/trinity-large-thinking:free": { + "id": "arcee-ai/trinity-large-thinking:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "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/coder-large": { + "id": "arcee-ai/coder-large", + "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 + } + }, + "bytedance-seed/dola-seed-2.0-pro:free": { + "id": "bytedance-seed/dola-seed-2.0-pro:free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "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-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 + } + }, + "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-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 + } + }, + "mancer/weaver": { + "id": "mancer/weaver", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 2000 + } + }, + "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/frontier": { + "id": "kilo-auto/frontier", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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/free": { + "id": "kilo-auto/free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 204800, + "output": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "morph/morph-v3-fast": { + "id": "morph/morph-v3-fast", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 16000 + }, + "family": "morph" + }, + "morph/morph-v3-large": { + "id": "morph/morph-v3-large", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + }, + "family": "morph" + }, + "eleutherai/llemma_7b": { + "id": "eleutherai/llemma_7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "alpindale/goliath-120b": { + "id": "alpindale/goliath-120b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 6144, + "output": 1024 + } + }, + "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/devstral-medium": { + "id": "mistralai/devstral-medium", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 26215 + } + }, + "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-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/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/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-2407": { + "id": "mistralai/mistral-large-2407", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "mistralai/voxtral-small-24b-2507": { + "id": "mistralai/Voxtral-Small-24B-2507", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 32000 + }, + "family": "voxtral" + }, + "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 + } + }, + "mistralai/devstral-small": { + "id": "mistralai/devstral-small", + "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 + } + }, + "meta-llama/llama-guard-3-8b": { + "id": "meta-llama/Llama-Guard-3-8B", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 1024, + "input": 8000 + } + }, + "meta-llama/llama-guard-4-12b": { + "id": "meta-llama/llama-guard-4-12b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 1024 + }, + "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 + } + }, + "x-ai/grok-4.20": { + "id": "x-ai/grok-4.20", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "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 + } + }, + "x-ai/grok-4.20-multi-agent": { + "id": "x-ai/grok-4.20-multi-agent", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "pdf", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + } + }, + "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-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.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 + } + }, + "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 + } + }, + "microsoft/phi-4": { + "id": "microsoft/phi-4", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16000, + "output": 4096 + }, + "family": "phi" + }, + "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 + } + }, + "cohere/command-a": { + "id": "cohere/command-a", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8000 + }, + "family": "command" + }, + "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 + } + }, + "nvidia/llama-3.3-nemotron-super-49b-v1.5": { + "id": "nvidia/llama-3.3-nemotron-super-49b-v1.5", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "nvidia/nemotron-nano-12b-v2-vl": { + "id": "nvidia/nemotron-nano-12b-v2-vl", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + }, + "family": "nemotron" + }, + "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": 128000, + "output": 4096 + } + }, + "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-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-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-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/o3-pro": { + "id": "openai/o3-pro", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000, + "input": 100000 + }, + "family": "o-pro" + }, + "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-4": { + "id": "openai/gpt-4", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + }, + "family": "gpt" + }, + "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": { + "id": "openai/gpt-audio", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "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-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-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-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-3.5-turbo-instruct": { + "id": "openai/gpt-3.5-turbo-instruct", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 4096, + "input": 4096 + }, + "family": "gpt" + }, + "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 + } + }, + "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 + } + }, + "relace/relace-apply-3": { + "id": "relace/relace-apply-3", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "relace/relace-search": { + "id": "relace/relace-search", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 128000 + } + }, + "qwen/qwen2.5-coder-7b-instruct": { + "id": "qwen/qwen2.5-coder-7b-instruct", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "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-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-max": { + "id": "qwen/qwen-max", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "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/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-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/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-turbo": { + "id": "qwen/qwen-turbo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "kwaipilot/kat-coder-pro-v2": { + "id": "kwaipilot/kat-coder-pro-v2", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + }, + "family": "kat-coder" + }, + "google/lyria-3-clip-preview": { + "id": "google/lyria-3-clip-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/lyria-3-pro-preview": { + "id": "google/lyria-3-pro-preview", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "audio", + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "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-2.5-flash-image": { + "id": "google/gemini-2.5-flash-image", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + }, + "family": "gemini-flash" + }, + "google/gemini-3.1-flash-image-preview": { + "id": "google/gemini-3.1-flash-image-preview", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + }, + "family": "gemini" + }, + "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/gemma-2-27b-it": { + "id": "google/gemma-2-27b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "thedrummer/unslopnemo-12b": { + "id": "thedrummer/unslopnemo-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/skyfall-36b-v2": { + "id": "thedrummer/skyfall-36b-v2", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "thedrummer/rocinante-12b": { + "id": "thedrummer/rocinante-12b", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "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 + } + }, + "anthropic/claude-opus-4.6-fast": { + "id": "anthropic/claude-opus-4.6-fast", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "image", + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "anthropic/claude-3-haiku": { + "id": "anthropic/claude-3-haiku", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + }, + "family": "claude-haiku" + }, + "switchpoint/router": { + "id": "switchpoint/router", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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 + } + }, + "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 + } + }, + "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-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-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-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 + } + }, + "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-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-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.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 + } + }, + "auto": { + "id": "auto", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "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 + } + }, + "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/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/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/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/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/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/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/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 + } + }, + "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/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/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/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/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/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-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-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/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.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.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.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.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.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-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-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/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/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/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/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/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/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/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/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-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/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/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/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 + } + }, + "anthropic/claude-opus-4-7": { + "id": "anthropic/claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 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-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.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 + } + }, + "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-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 + } + }, + "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-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, + "input": 128000, + "output": 64000 + } + }, + "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-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 + } + }, + "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-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-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 + } + }, + "glm-5v-turbo": { + "id": "glm-5v-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "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 + } + }, + "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.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-flash", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "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": 64000 + } + }, + "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.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 + } + }, + "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-7": { + "id": "claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "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 + } + }, + "big-pickle": { + "id": "big-pickle", + "family": "big-pickle", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "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 + } + }, + "claude-3-5-haiku": { + "id": "claude-3-5-haiku", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "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 + } + }, + "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.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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "qwen3.6-plus-free": { + "id": "qwen3.6-plus-free", + "family": "qwen-free", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1048576, + "output": 64000 + } + }, + "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 + } + }, + "grok-code": { + "id": "grok-code", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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": 204800, + "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 + } + }, + "step-3.5-flash-2603": { + "id": "step-3.5-flash-2603", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "input": 256000, + "output": 256000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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/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/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 + } + }, + "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-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 + } + }, + "google/gemma-2-2b-it": { + "id": "google/gemma-2-2b-it", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "input": 8000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "novita/kimi-k2.5": { + "id": "novita/kimi-k2.5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "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/glm-5": { + "id": "novita/glm-5", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 205000, + "output": 131072 + } + }, + "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/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/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 + } + }, + "novita/deepseek-v3.2": { + "id": "novita/deepseek-v3.2", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "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/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 + } + }, + "fireworks-ai/kimi-k2.5-fw": { + "id": "fireworks-ai/kimi-k2.5-fw", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "input": 245760, + "output": 16384 + } + }, + "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 + } + }, + "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-music": { + "id": "elevenlabs/elevenlabs-music", + "family": "elevenlabs", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 2000, + "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": 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": 128000, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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-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-3-mini": { + "id": "xai/grok-3-mini", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "xai/grok-4.20-multi-agent": { + "id": "xai/grok-4.20-multi-agent", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 2000000 + }, + "family": "grok" + }, + "xai/grok-3": { + "id": "xai/grok-3", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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/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-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/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/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-5.3-codex-spark": { + "id": "openai/gpt-5.3-codex-spark", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "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/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-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/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-image-1.5": { + "id": "openai/gpt-image-1.5", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 128000, + "output": 0 + } + }, + "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 + } + }, + "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 + } + }, + "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/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-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/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/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/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/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/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/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-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/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/lyria": { + "id": "google/lyria", + "family": "lyria", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 0, + "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-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/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/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 + } + }, + "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/gemma-4-31b": { + "id": "google/gemma-4-31b", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 8192 + } + }, + "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/veo-2": { + "id": "google/veo-2", + "family": "veo", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "video" + ] + }, + "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 + } + }, + "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-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 + } + }, + "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.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 + } + }, + "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-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-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 + } + }, + "trytako/tako": { + "id": "trytako/tako", + "family": "tako", + "reasoning": false, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2048, + "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 + } + }, + "mistral-nemo": { + "id": "mistral-nemo", + "family": "mistral-nemo", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "gemma2-9b-it": { + "id": "gemma2-9b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "llama-4-scout": { + "id": "llama-4-scout", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "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 + } + }, + "hermes-2-pro-llama-3-8b": { + "id": "hermes-2-pro-llama-3-8b", + "family": "nousresearch", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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": 32768, + "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 + } + }, + "o1": { + "id": "o1", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 100000 + } + }, + "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": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "grok-4": { + "id": "grok-4", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "sonar-reasoning": { + "id": "sonar-reasoning", + "family": "sonar-reasoning", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 127000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "qwen3-vl-235b-a22b-instruct": { + "id": "qwen3-vl-235b-a22b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "grok-3": { + "id": "grok-3", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "gpt-oss:20b": { + "id": "gpt-oss:20b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "gemma4:31b": { + "id": "gemma4:31b", + "family": "gemma", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 8192 + } + }, + "gpt-oss:120b": { + "id": "gpt-oss:120b", + "family": "gpt-oss", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 32768 + } + }, + "qwen3.5:397b": { + "id": "qwen3.5:397b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 81920 + } + }, + "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 + } + }, + "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 + } + }, + "gemma3:4b": { + "id": "gemma3:4b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "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 + } + }, + "qwen3-vl:235b": { + "id": "qwen3-vl:235b", + "family": "qwen", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "rnj-1:8b": { + "id": "rnj-1:8b", + "family": "rnj", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 4096 + } + }, + "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 + } + }, + "ministral-3:8b": { + "id": "ministral-3:8b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "gemma3:12b": { + "id": "gemma3:12b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "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:3b": { + "id": "ministral-3:3b", + "family": "ministral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 128000 + } + }, + "gemma3:27b": { + "id": "gemma3:27b", + "family": "gemma", + "reasoning": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "devstral-2:123b": { + "id": "devstral-2:123b", + "family": "devstral", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "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 + } + }, + "qwen3-coder-next": { + "id": "qwen3-coder-next", + "family": "qwen", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144, + "input": 262144 + }, + "temperature": true + }, + "nemotron-3-super": { + "id": "nemotron-3-super", + "family": "nemotron", + "reasoning": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "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 + } + }, + "kimi-k2:1t": { + "id": "kimi-k2:1t", + "family": "kimi", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "nvidia.nemotron-super-3-120b": { + "id": "nvidia.nemotron-super-3-120b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 131072 + } + }, + "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 + } + }, + "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 + } + }, + "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.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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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.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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "global.anthropic.claude-opus-4-7": { + "id": "global.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "zai.glm-5": { + "id": "zai.glm-5", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 101376 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "us.anthropic.claude-opus-4-7": { + "id": "us.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "anthropic.claude-opus-4-7": { + "id": "anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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.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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "eu.anthropic.claude-opus-4-7": { + "id": "eu.anthropic.claude-opus-4-7", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "minimax.minimax-m2.5": { + "id": "minimax.minimax-m2.5", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 98304 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "qwen.qwen3-coder-next": { + "id": "qwen.qwen3-coder-next", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 65536 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "text-prime": { + "id": "text-prime", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 30000 + } + }, + "text-standard": { + "id": "text-standard", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "text-max": { + "id": "text-max", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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 + } + }, + "glm-4.6v-flash": { + "id": "glm-4.6v-flash", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "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 + } + }, + "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 + } + }, + "grok-4-20-multi-agent": { + "id": "grok-4-20-multi-agent", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "z-ai-glm-5v-turbo": { + "id": "z-ai-glm-5v-turbo", + "family": "glmv", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32768 + } + }, + "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 + } + }, + "nvidia-nemotron-cascade-2-30b-a3b": { + "id": "nvidia-nemotron-cascade-2-30b-a3b", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 32768 + } + }, + "grok-4-20": { + "id": "grok-4-20", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 128000 + } + }, + "google-gemma-4-26b-a4b-it": { + "id": "google-gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "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 + } + }, + "qwen3-5-397b-a17b": { + "id": "qwen3-5-397b-a17b", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "minimax-m27": { + "id": "minimax-m27", + "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 + } + }, + "mercury-2": { + "id": "mercury-2", + "family": "mercury", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 50000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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.6": { + "id": "zai-org-glm-4.6", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "output": 16384 + } + }, + "mistral-small-2603": { + "id": "mistral-small-2603", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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 + } + }, + "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": 32768 + } + }, + "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 + } + }, + "openai-gpt-54-mini": { + "id": "openai-gpt-54-mini", + "family": "gpt-mini", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 400000, + "output": 128000 + } + }, + "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-5-1": { + "id": "zai-org-glm-5-1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 24000 + } + }, + "qwen-3-6-plus": { + "id": "qwen-3-6-plus", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 64000 + } + }, + "aion-labs-aion-2-0": { + "id": "aion-labs-aion-2-0", + "family": "o", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "arcee-trinity-large-thinking": { + "id": "arcee-trinity-large-thinking", + "family": "trinity", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 65536 + } + }, + "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 + } + }, + "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 + } + }, + "claude-opus-4-6-fast": { + "id": "claude-opus-4-6-fast", + "family": "claude-opus", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "z-ai-glm-5-turbo": { + "id": "z-ai-glm-5-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 32768 + } + }, + "google-gemma-4-31b-it": { + "id": "google-gemma-4-31b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "video" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "coding-glm-5.1": { + "id": "coding-glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, "llama3.1-8b": { "id": "llama3.1-8b", "family": "llama", @@ -38913,6 +31518,25 @@ "output": 8000 } }, + "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 + } + }, "zai-glm-4.7": { "id": "zai-glm-4.7", "reasoning": false, @@ -38931,8 +31555,1184 @@ "output": 40000 } }, - "gpt-5.3-chat": { - "id": "gpt-5.3-chat", + "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 + } + }, + "zai-glm-5-1": { + "id": "zai-glm-5-1", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 198000, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "codestral-2501": { + "id": "codestral-2501", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "phi-4": { + "id": "phi-4", + "family": "phi", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 4096 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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-4": { + "id": "gpt-4", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "model-router": { + "id": "model-router", + "family": "model-router", + "reasoning": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "o1-preview": { + "id": "o1-preview", + "family": "o", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 32768 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "ministral-3b": { + "id": "ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "gpt-5.2-chat": { + "id": "gpt-5.2-chat", "family": "gpt-codex", "reasoning": true, "temperature": false, @@ -38951,127 +32751,9 @@ "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", + "command-r7b-12-2024": { + "id": "command-r7b-12-2024", + "family": "command-r", "reasoning": false, "temperature": true, "toolCall": true, @@ -39085,49 +32767,232 @@ }, "limit": { "context": 128000, - "output": 128000 + "output": 4000 } }, - "claude-opus4-5": { - "id": "claude-opus4-5", - "family": "claude-opus", - "reasoning": true, + "c4ai-aya-vision-8b": { + "id": "c4ai-aya-vision-8b", + "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text", - "image", - "pdf" + "image" ], "output": [ "text" ] }, "limit": { - "context": 200000, - "output": 200000 + "context": 16000, + "output": 4000 } }, - "claude-4-5-sonnet": { - "id": "claude-4-5-sonnet", - "family": "claude-sonnet", - "reasoning": true, + "command-r-plus-08-2024": { + "id": "command-r-plus-08-2024", + "family": "command-r", + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text", - "image", - "pdf" + "text" ], "output": [ "text" ] }, "limit": { - "context": 200000, - "output": 200000 + "context": 128000, + "output": 4000 + } + }, + "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 + } + }, + "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-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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 } }, "grok-2-1212": { @@ -39149,12 +33014,109 @@ "output": 8192 } }, - "grok-4.20-multi-agent-0309": { - "id": "grok-4.20-multi-agent-0309", + "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-3-mini-fast": { + "id": "grok-3-mini-fast", "family": "grok", "reasoning": true, "temperature": true, - "toolCall": false, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "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-fast": { + "id": "grok-3-fast", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "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-4.20-0309-reasoning": { + "id": "grok-4.20-0309-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, "modalities": { "input": [ "text", @@ -39169,105 +33131,8 @@ "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", + "grok-3-mini-fast-latest": { + "id": "grok-3-mini-fast-latest", "family": "grok", "reasoning": true, "temperature": true, @@ -39324,10 +33189,29 @@ "output": 8192 } }, - "grok-4-1-fast": { - "id": "grok-4-1-fast", + "grok-2": { + "id": "grok-2", "family": "grok", - "reasoning": true, + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "grok-4.20-0309-non-reasoning": { + "id": "grok-4.20-0309-non-reasoning", + "family": "grok", + "reasoning": false, "temperature": true, "toolCall": true, "modalities": { @@ -39344,32 +33228,12 @@ "output": 30000 } }, - "grok-2-vision-latest": { - "id": "grok-2-vision-latest", + "grok-3-fast-latest": { + "id": "grok-3-fast-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" @@ -39383,31 +33247,12 @@ "output": 8192 } }, - "grok-3-mini-fast-latest": { - "id": "grok-3-mini-fast-latest", + "grok-4.20-multi-agent-0309": { + "id": "grok-4.20-multi-agent-0309", "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, + "toolCall": false, "modalities": { "input": [ "text", @@ -39441,9 +33286,28 @@ "output": 8192 } }, - "grok-vision-beta": { - "id": "grok-vision-beta", - "family": "grok-vision", + "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-2-vision": { + "id": "grok-2-vision", + "family": "grok", "reasoning": false, "temperature": true, "toolCall": true, @@ -39461,8 +33325,5312 @@ "output": 4096 } }, - "grok-4.20-0309-non-reasoning": { - "id": "grok-4.20-0309-non-reasoning", + "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-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 + } + }, + "mistralai/mistral-small-3.2-24b-instruct-2506": { + "id": "mistralai/Mistral-Small-3.2-24B-Instruct-2506", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 8192 + } + }, + "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 + } + }, + "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-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-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-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-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-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-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-opus-4-7@default": { + "id": "claude-opus-4-7@default", + "family": "claude-opus", + "reasoning": true, + "temperature": false, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + }, + "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 + }, + "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 + } + }, + "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 + }, + "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 + }, + "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-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.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-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.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-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: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.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.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:qwen/qwen3.5-397b-a17b": { + "id": "hf:Qwen/Qwen3.5-397B-A17B", + "family": "qwen", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "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-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 + } + }, + "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/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: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-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-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.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.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: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: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: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:nvidia/nvidia-nemotron-3-super-120b-a12b-nvfp4": { + "id": "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", + "family": "nemotron", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 65536 + } + }, + "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: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.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:zai-org/glm-5.1": { + "id": "hf:zai-org/GLM-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 65536 + } + }, + "hf:zai-org/glm-5": { + "id": "hf:zai-org/GLM-5", + "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 + } + }, + "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 + } + }, + "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-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/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/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 + } + }, + "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.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-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" + }, + "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-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-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" + }, + "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/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/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/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/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.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/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 + } + }, + "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 + } + }, + "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 + } + }, + "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.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/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/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/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-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/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.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-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 + } + }, + "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 + } + }, + "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/codegemma-7b": { + "id": "google/codegemma-7b", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "mercury-edit-2": { + "id": "mercury-edit-2", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "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 + } + }, + "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-image-1": { + "id": "gpt-image-1", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "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 + } + }, + "gpt-image-1-mini": { + "id": "gpt-image-1-mini", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "gpt-3.5-turbo": { + "id": "gpt-3.5-turbo", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 16385, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "chatgpt-image-latest": { + "id": "chatgpt-image-latest", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "gpt-image-1.5": { + "id": "gpt-image-1.5", + "family": "gpt-image", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 0, + "input": 0, + "output": 0 + } + }, + "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 + } + }, + "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 + } + }, + "glm-5-fp8": { + "id": "GLM-5-FP8", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "mistral-small-latest": { + "id": "mistral-small-latest", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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-2512": { + "id": "devstral-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "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 + } + }, + "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": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "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 + } + }, + "mistral-large-latest": { + "id": "mistral-large-latest", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "mistral-small-2506": { + "id": "mistral-small-2506", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "pixtral-12b": { + "id": "pixtral-12b", + "family": "pixtral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "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 + } + }, + "mistral-embed": { + "id": "mistral-embed", + "family": "mistral-embed", + "reasoning": false, + "temperature": false, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8000, + "output": 3072 + } + }, + "magistral-small": { + "id": "magistral-small", + "family": "magistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "devstral-small-2507": { + "id": "devstral-small-2507", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "devstral-small-2512": { + "id": "devstral-small-2512", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 262000 + } + }, + "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-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 + } + }, + "intellect-3": { + "id": "intellect-3", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "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 + } + }, + "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 + } + }, + "zai-org/glm-5v-turbo": { + "id": "zai-org/GLM-5V-Turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 131072 + } + }, + "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-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/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/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.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.6-plus": { + "id": "alibaba/qwen3.6-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/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-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-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-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-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-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-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-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-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-coder": { + "id": "alibaba/qwen3-coder", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 66536 + } + }, + "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.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/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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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-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-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-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-4": { + "id": "voyage/voyage-4", + "family": "voyage", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32000, + "output": 0 + } + }, + "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-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-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 + } + }, + "zai/glm-5v-turbo": { + "id": "zai/glm-5v-turbo", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 128000 + } + }, + "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-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-5.1": { + "id": "zai/glm-5.1", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 202752, + "output": 202752 + } + }, + "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-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.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-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.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.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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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-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-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-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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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/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-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/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 + } + }, + "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-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/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-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-micro": { + "id": "amazon/nova-micro", + "family": "nova-micro", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "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/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/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/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/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/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/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-small": { + "id": "mistral/devstral-small", + "family": "devstral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 64000 + } + }, + "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/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/mistral-small": { + "id": "mistral/mistral-small", + "family": "mistral-small", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 256000 + } + }, + "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/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/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/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/ministral-3b": { + "id": "mistral/ministral-3b", + "family": "ministral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "mistral/codestral": { + "id": "mistral/codestral", + "family": "codestral", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 4096 + } + }, + "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.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-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-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-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.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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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/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-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/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/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/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 + } + }, + "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/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/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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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-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 + } + }, + "gpt-4o-mini-search-preview": { + "id": "gpt-4o-mini-search-preview", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "grok-4-20-beta-0309-non-reasoning": { + "id": "grok-4-20-beta-0309-non-reasoning", "family": "grok", "reasoning": false, "temperature": true, @@ -39481,65 +38649,8 @@ "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", + "qwen-coder-plus": { + "id": "qwen-coder-plus", "family": "qwen", "reasoning": false, "temperature": true, @@ -39557,66 +38668,9 @@ "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", + "gemma-3n-e4b-it": { + "id": "gemma-3n-e4b-it", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": false, @@ -39630,53 +38684,35 @@ }, "limit": { "context": 8192, - "output": 1024 + "output": 2000 } }, - "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", + "glm-4.6v-flashx": { + "id": "glm-4.6v-flashx", + "family": "glm", "reasoning": true, "temperature": true, "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16000 + } + }, + "gemma-2-27b-it-together": { + "id": "gemma-2-27b-it-together", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -39686,12 +38722,50 @@ ] }, "limit": { - "context": 32768, + "context": 8192, "output": 16384 } }, - "qwen3.5-flash": { - "id": "qwen3.5-flash", + "codestral-2508": { + "id": "codestral-2508", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "gemma-3-1b-it": { + "id": "gemma-3-1b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 16384 + } + }, + "qwen35-397b-a17b": { + "id": "qwen35-397b-a17b", "family": "qwen", "reasoning": true, "temperature": true, @@ -39699,21 +38773,20 @@ "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, + "context": 262144, "output": 65536 } }, - "qwen2-5-math-7b-instruct": { - "id": "qwen2-5-math-7b-instruct", - "family": "qwen", + "glm-4-32b-0414-128k": { + "id": "glm-4-32b-0414-128k", + "family": "glm", "reasoning": false, "temperature": true, "toolCall": true, @@ -39726,114 +38799,100 @@ ] }, "limit": { - "context": 4096, - "output": 3072 + "context": 128000, + "output": 16384 } }, - "deepseek-r1-distill-qwen-1-5b": { - "id": "deepseek-r1-distill-qwen-1-5b", - "family": "qwen", + "seed-1-6-flash-250715": { + "id": "seed-1-6-flash-250715", + "family": "seed", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 256000, "output": 16384 } }, - "deepseek-r1-distill-qwen-7b": { - "id": "deepseek-r1-distill-qwen-7b", - "family": "qwen", + "seed-1-6-250615": { + "id": "seed-1-6-250615", + "family": "seed", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 256000, "output": 16384 } }, - "qwen-deep-research": { - "id": "qwen-deep-research", + "cogview-4": { + "id": "cogview-4", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen2-5-vl-32b-instruct": { + "id": "qwen2-5-vl-32b-instruct", "family": "qwen", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 1000000, + "context": 131072, "output": 32768 } }, - "qwen2-5-math-72b-instruct": { - "id": "qwen2-5-math-72b-instruct", + "qwen3-vl-8b-instruct": { + "id": "qwen3-vl-8b-instruct", "family": "qwen", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "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" + "text", + "image" ], "output": [ "text" @@ -39844,238 +38903,89 @@ "output": 8192 } }, - "kimi/kimi-k2.5": { - "id": "kimi/kimi-k2.5", - "family": "kimi", + "claude-3-7-sonnet": { + "id": "claude-3-7-sonnet", + "family": "claude", "reasoning": true, - "temperature": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "grok-4-20-beta-0309-reasoning": { + "id": "grok-4-20-beta-0309-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, "toolCall": true, "modalities": { "input": [ "text", - "image", - "video" + "image" ], "output": [ "text" ] }, "limit": { - "context": 262144, - "output": 262144 + "context": 2000000, + "output": 30000 } }, - "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", + "grok-imagine-image": { + "id": "grok-imagine-image", + "family": "grok", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ - "text" + "text", + "image" ] }, "limit": { - "context": 163840, - "output": 163840 + "context": 2000, + "output": 4096 } }, - "siliconflow/deepseek-v3.1-terminus": { - "id": "siliconflow/deepseek-v3.1-terminus", - "family": "deepseek", + "gemini-pro-latest": { + "id": "gemini-pro-latest", + "family": "gemini", "reasoning": true, "temperature": true, "toolCall": true, "modalities": { "input": [ - "text" + "text", + "image" ], "output": [ "text" ] }, "limit": { - "context": 163840, + "context": 1048576, "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", + "mixtral-8x7b-instruct-together": { + "id": "mixtral-8x7b-instruct-together", + "family": "mistral", "reasoning": false, "temperature": true, "toolCall": false, @@ -40089,15 +38999,35 @@ }, "limit": { "context": 32768, - "output": 8192 + "output": 16384 } }, - "nousresearch/deephermes-3-mistral-24b-preview": { - "id": "NousResearch/DeepHermes-3-Mistral-24B-Preview", - "family": "nousresearch", + "seedream-4-0": { + "id": "seedream-4-0", + "family": "seed", "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "minimax-text-01": { + "id": "minimax-text-01", + "family": "minimax", + "reasoning": false, + "temperature": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -40107,16 +39037,16 @@ ] }, "limit": { - "context": 32768, - "output": 32768 + "context": 1000000, + "output": 131072 } }, - "nousresearch/hermes-4-14b": { - "id": "NousResearch/Hermes-4-14B", - "family": "nousresearch", - "reasoning": true, + "qwen3-32b-fp8": { + "id": "qwen3-32b-fp8", + "family": "qwen", + "reasoning": false, "temperature": true, - "toolCall": true, + "toolCall": false, "modalities": { "input": [ "text" @@ -40127,202 +39057,12 @@ }, "limit": { "context": 40960, - "output": 40960 + "output": 20000 } }, - "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", + "llama-4-scout-17b-instruct": { + "id": "llama-4-scout-17b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40336,13 +39076,51 @@ ] }, "limit": { - "context": 131072, - "output": 131072 + "context": 8192, + "output": 2048 } }, - "unsloth/mistral-nemo-instruct-2407": { - "id": "unsloth/Mistral-Nemo-Instruct-2407", - "family": "unsloth", + "qwen3-4b-fp8": { + "id": "qwen3-4b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 20000 + } + }, + "veo-3.1-generate-preview": { + "id": "veo-3.1-generate-preview", + "family": "gemini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 1 + } + }, + "llama-guard-4-12b": { + "id": "llama-guard-4-12b", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40356,12 +39134,73 @@ }, "limit": { "context": 131072, - "output": 131072 + "output": 16384 } }, - "unsloth/mistral-small-24b-instruct-2501": { - "id": "unsloth/Mistral-Small-24B-Instruct-2501", - "family": "unsloth", + "gemma-3n-e2b-it": { + "id": "gemma-3n-e2b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2000 + } + }, + "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 + } + }, + "ministral-8b-2512": { + "id": "ministral-8b-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 16384 + } + }, + "gemma-3-27b": { + "id": "gemma-3-27b", + "family": "gemma", "reasoning": false, "temperature": true, "toolCall": true, @@ -40374,13 +39213,627 @@ "text" ] }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "grok-imagine-image-pro": { + "id": "grok-imagine-image-pro", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen3-vl-flash": { + "id": "qwen3-vl-flash", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 32768 + } + }, + "llama-3.1-70b-instruct": { + "id": "llama-3.1-70b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 2048 + } + }, + "seed-1-8-251228": { + "id": "seed-1-8-251228", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "seed-1-6-250915": { + "id": "seed-1-6-250915", + "family": "seed", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 16384 + } + }, + "glm-4.5-x": { + "id": "glm-4.5-x", + "family": "glm", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "veo-3.1-fast-generate-preview": { + "id": "veo-3.1-fast-generate-preview", + "family": "gemini", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 1 + } + }, + "gemma-3-4b-it": { + "id": "gemma-3-4b-it", + "family": "gemma", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, "limit": { "context": 32768, + "output": 8192 + } + }, + "qwen-image-max": { + "id": "qwen-image-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "claude-3-5-sonnet": { + "id": "claude-3-5-sonnet", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 16384 + } + }, + "qwen-image-max-2025-12-30": { + "id": "qwen-image-max-2025-12-30", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "ministral-3b-2512": { + "id": "ministral-3b-2512", + "family": "mistral", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 16384 + } + }, + "grok-4-20-multi-agent-beta-0309": { + "id": "grok-4-20-multi-agent-beta-0309", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 2000000, + "output": 30000 + } + }, + "qwen-plus-latest": { + "id": "qwen-plus-latest", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 1000000, + "output": 32000 + } + }, + "seedream-4-5": { + "id": "seedream-4-5", + "family": "seed", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "llama-3.1-nemotron-ultra-253b": { + "id": "llama-3.1-nemotron-ultra-253b", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "llama-4-maverick-17b-instruct": { + "id": "llama-4-maverick-17b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 2048 + } + }, + "qwen-image-edit-plus": { + "id": "qwen-image-edit-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen3-30b-a3b-fp8": { + "id": "qwen3-30b-a3b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "minimax-m2.1-lightning": { + "id": "minimax-m2.1-lightning", + "family": "minimax", + "reasoning": true, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 196608, + "output": 131072 + } + }, + "claude-3-haiku": { + "id": "claude-3-haiku", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "glm-image": { + "id": "glm-image", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "qwen-image-edit-max": { + "id": "qwen-image-edit-max", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "llama-3.2-3b-instruct": { + "id": "llama-3.2-3b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 32768, + "output": 32000 + } + }, + "qwen-image-plus": { + "id": "qwen-image-plus", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text", + "image" + ] + }, + "limit": { + "context": 2000, + "output": 4096 + } + }, + "gpt-4o-search-preview": { + "id": "gpt-4o-search-preview", + "family": "gpt", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "custom": { + "id": "custom", + "family": "auto", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "qwen3-vl-30b-a3b-instruct": { + "id": "qwen3-vl-30b-a3b-instruct", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, "output": 32768 } }, - "unsloth/llama-3.2-1b-instruct": { - "id": "unsloth/Llama-3.2-1B-Instruct", + "qwen3-235b-a22b-fp8": { + "id": "qwen3-235b-a22b-fp8", + "family": "qwen", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 40960, + "output": 20000 + } + }, + "llama-3-8b-instruct": { + "id": "llama-3-8b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "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 + } + }, + "qwen25-coder-7b": { + "id": "qwen25-coder-7b", + "family": "qwen", "reasoning": false, "temperature": true, "toolCall": false, @@ -40397,9 +39850,9 @@ "output": 8192 } }, - "unsloth/llama-3.2-3b-instruct": { - "id": "unsloth/Llama-3.2-3B-Instruct", - "family": "unsloth", + "llama-3-70b-instruct": { + "id": "llama-3-70b-instruct", + "family": "llama", "reasoning": false, "temperature": true, "toolCall": false, @@ -40412,13 +39865,71 @@ ] }, "limit": { - "context": 16384, + "context": 8192, + "output": 8000 + } + }, + "glm-4.5-airx": { + "id": "glm-4.5-airx", + "family": "glm", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, "output": 16384 } }, - "moonshotai/kimi-k2.5-tee": { - "id": "moonshotai/Kimi-K2.5-TEE", - "family": "kimi", + "llama-3.2-11b-instruct": { + "id": "llama-3.2-11b-instruct", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "claude-3-opus": { + "id": "claude-3-opus", + "family": "claude", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 200000, + "output": 4096 + } + }, + "gemini-flash-lite-latest": { + "id": "gemini-flash-lite-latest", + "family": "gemini-flash-lite", "reasoning": true, "temperature": true, "toolCall": true, @@ -40426,209 +39937,165 @@ "input": [ "text", "image", - "video" + "audio", + "video", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 262144, - "output": 65535 + "context": 1048576, + "output": 65536 } }, - "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", + "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" + "image", + "video", + "audio", + "pdf" ], "output": [ "text" ] }, "limit": { - "context": 262144, + "context": 1048576, "output": 65536 } }, - "qwen/qwen3-coder-480b-a35b-instruct-fp8-tee": { - "id": "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE", - "family": "qwen", + "gemini-embedding-001": { + "id": "gemini-embedding-001", + "family": "gemini", "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, + "temperature": false, "toolCall": false, "modalities": { "input": [ - "text", - "image" + "text" ], "output": [ "text" ] }, "limit": { - "context": 32768, + "context": 2048, + "output": 3072 + } + }, + "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 + } + }, + "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.2-maas": { + "id": "deepseek-ai/deepseek-v3.2-maas", + "family": "deepseek", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "pdf" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 163840, + "output": 65536 + } + }, + "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/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", + "openai/gpt-oss-120b-maas": { + "id": "openai/gpt-oss-120b-maas", "family": "gpt-oss", "reasoning": true, "temperature": true, @@ -40643,12 +40110,432 @@ }, "limit": { "context": 131072, - "output": 65536 + "output": 32768 } }, - "chutesai/mistral-small-3.1-24b-instruct-2503": { - "id": "chutesai/Mistral-Small-3.1-24B-Instruct-2503", - "family": "chutesai", + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "moonshotai/kimi-k2-thinking-maas": { + "id": "moonshotai/kimi-k2-thinking-maas", + "family": "kimi-thinking", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262144, + "output": 262144 + } + }, + "@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/openai/gpt-oss-20b": { + "id": "@cf/openai/gpt-oss-20b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/openai/gpt-oss-120b": { + "id": "@cf/openai/gpt-oss-120b", + "reasoning": true, + "temperature": true, + "toolCall": true, + "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": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 128000, + "output": 16384 + } + }, + "@cf/google/gemma-4-26b-a4b-it": { + "id": "@cf/google/gemma-4-26b-a4b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "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 + } + }, + "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-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 + } + }, + "allam-2-7b": { + "id": "allam-2-7b", + "family": "allam", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 4096, + "output": 4096 + } + }, + "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 + } + }, + "whisper-large-v3-turbo": { + "id": "whisper-large-v3-turbo", + "family": "whisper", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "audio" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 448, + "output": 448 + } + }, + "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 + } + }, + "canopylabs/orpheus-arabic-saudi": { + "id": "canopylabs/orpheus-arabic-saudi", + "family": "canopylabs", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 4000, + "output": 50000 + } + }, + "canopylabs/orpheus-v1-english": { + "id": "canopylabs/orpheus-v1-english", + "family": "canopylabs", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "audio" + ] + }, + "limit": { + "context": 4000, + "output": 50000 + } + }, + "meta-llama/llama-prompt-guard-2-22m": { + "id": "meta-llama/llama-prompt-guard-2-22m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "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, @@ -40663,12 +40550,1734 @@ }, "limit": { "context": 131072, + "output": 8192 + } + }, + "meta-llama/llama-prompt-guard-2-86m": { + "id": "meta-llama/llama-prompt-guard-2-86m", + "family": "llama", + "reasoning": false, + "temperature": true, + "toolCall": false, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 512, + "output": 512 + } + }, + "groq/compound": { + "id": "groq/compound", + "family": "groq", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "groq/compound-mini": { + "id": "groq/compound-mini", + "family": "groq", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "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 + } + }, + "grok-4-20-non-reasoning": { + "id": "grok-4-20-non-reasoning", + "family": "grok", + "reasoning": false, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "output": 8192 + } + }, + "grok-4-20-reasoning": { + "id": "grok-4-20-reasoning", + "family": "grok", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 262000, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "hunyuan-turbos": { + "id": "hunyuan-turbos", + "family": "hunyuan", + "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 + } + }, + "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-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 + } + }, + "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-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-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 + } + }, + "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 + } + }, + "gemma-4-31b-it": { + "id": "gemma-4-31b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "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 + } + }, + "gemma-4-26b-it": { + "id": "gemma-4-26b-it", + "family": "gemma", + "reasoning": true, + "temperature": true, + "toolCall": true, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "limit": { + "context": 256000, + "output": 8192 + } + }, + "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-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 + } + }, + "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 } }, - "opengvlab/internvl3-78b-tee": { - "id": "OpenGVLab/InternVL3-78B-TEE", - "family": "opengvlab", + "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 + } + }, + "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 + } + }, + "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/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-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 + } + }, + "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/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 + } + }, + "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-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": { + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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/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/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.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-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/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 + } + }, + "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/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/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-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/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/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 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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-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-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-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-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 + } + }, + "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-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-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-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-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-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-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-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 + } + }, + "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 + } + }, + "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 + } + }, + "deepseek-ai/deepseek-ocr/models/deepseek-ocr": { + "id": "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR", + "family": "deepseek", "reasoning": false, "temperature": true, "toolCall": false, @@ -40681,9 +42290,188 @@ "text" ] }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "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 + } + }, + "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 + } + }, + "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 + } + }, + "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-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 + } + }, + "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 + } + }, + "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": 32768 + "output": 4096 + } + }, + "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 } } } diff --git a/src/hooks/AGENTS.md b/src/hooks/AGENTS.md index a0f9f80f9..135338424 100644 --- a/src/hooks/AGENTS.md +++ b/src/hooks/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/ — 52 Lifecycle Hooks -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts b/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts index 4c1ef6330..28dd23415 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts @@ -84,7 +84,7 @@ describe("executeCompact lock management", () => { let pluginConfig: ReturnType const sessionID = "test-session-123" const directory = "/test/dir" - const msg = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const msg = { providerID: "anthropic", modelID: "claude-opus-4-7" } beforeEach(() => { // given: Fresh state for each test @@ -132,7 +132,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) @@ -157,7 +157,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) @@ -352,7 +352,7 @@ describe("executeCompact lock management", () => { expect(mockClient.session.summarize).toHaveBeenCalledWith( expect.objectContaining({ path: { id: sessionID }, - body: { providerID: "anthropic", modelID: "claude-opus-4-6", auto: true }, + body: { providerID: "anthropic", modelID: "claude-opus-4-7", auto: true }, }), ) diff --git a/src/hooks/anthropic-effort/hook.ts b/src/hooks/anthropic-effort/hook.ts index 6d4cc965c..a545768d6 100644 --- a/src/hooks/anthropic-effort/hook.ts +++ b/src/hooks/anthropic-effort/hook.ts @@ -1,4 +1,4 @@ -import { log, normalizeModelID } from "../../shared" +import { isProviderUsingOAuth, log, normalizeModelID } from "../../shared" const OPUS_PATTERN = /claude-.*opus/i const EFFORT_UNSUPPORTED_PATTERN = /claude-.*haiku/i @@ -25,6 +25,18 @@ function shouldSkipForInternalAgent(agentName: string | undefined): boolean { return INTERNAL_SKIP_AGENTS.has(agentName.trim().toLowerCase()) } +/** + * Providers that expose constrained APIs rejecting `output_config.effort: "max"` + * (supported values: low | medium | high). Includes: + * - Anthropic OAuth (Claude Pro/Max via third-party clients) + * - GitHub Copilot (proxied Anthropic, doesn't support "max") + */ +function isConstrainedProvider(providerID: string): boolean { + if (providerID === "github-copilot") return true + if (providerID === "anthropic") return isProviderUsingOAuth(providerID) + return false +} + interface ChatParamsInput { sessionID: string agent: { name?: string } @@ -49,8 +61,9 @@ const MAX_VARIANT_BY_TIER: Record = { default: "high", } -function clampVariant(variant: string, isOpus: boolean): string { +function clampVariant(variant: string, isOpus: boolean, isConstrained: boolean): string { if (variant !== "max") return variant + if (isConstrained) return MAX_VARIANT_BY_TIER.default return isOpus ? MAX_VARIANT_BY_TIER.opus : MAX_VARIANT_BY_TIER.default } @@ -65,21 +78,27 @@ export function createAnthropicEffortHook() { if (isEffortUnsupportedModel(model.modelID)) return if (message.variant !== "max") return if (!isClaudeProvider(model.providerID, model.modelID)) return - if (model.providerID === "github-copilot") return if (shouldSkipForInternalAgent(agent?.name)) return if (output.options.effort !== undefined) return const opus = isOpusModel(model.modelID) - const clamped = clampVariant(message.variant, opus) + const constrained = isConstrainedProvider(model.providerID) + const clamped = clampVariant(message.variant, opus, constrained) output.options.effort = clamped - if (!opus) { - // Override the variant so OpenCode doesn't pass "max" to the API + const shouldOverrideMessageVariant = !opus || constrained + + if (shouldOverrideMessageVariant) { + // Override the variant so OpenCode doesn't pass "max" to the API. + // Non-Opus models cap at high; Anthropic OAuth (Claude Pro/Max) also + // caps at high even on Opus because the OAuth API only accepts + // low | medium | high. ;(message as { variant?: string }).variant = clamped - log("anthropic-effort: clamped variant max→high for non-Opus model", { + log("anthropic-effort: clamped variant max→high", { sessionID: input.sessionID, provider: model.providerID, model: model.modelID, + reason: constrained ? "constrained-provider" : "non-opus", }) } else { log("anthropic-effort: injected effort=max", { diff --git a/src/hooks/anthropic-effort/index.test.ts b/src/hooks/anthropic-effort/index.test.ts index cea012eb9..129b6513e 100644 --- a/src/hooks/anthropic-effort/index.test.ts +++ b/src/hooks/anthropic-effort/index.test.ts @@ -1,4 +1,9 @@ -import { describe, expect, it } from "bun:test" +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import * as path from "node:path" + +import { _resetProviderAuthCacheForTesting } from "../../shared/opencode-provider-auth" import { createAnthropicEffortHook } from "./index" interface ChatParamsInput { @@ -24,7 +29,7 @@ function createMockParams(overrides: { existingOptions?: Record }): { input: ChatParamsInput; output: ChatParamsOutput } { const providerID = overrides.providerID ?? "anthropic" - const modelID = overrides.modelID ?? "claude-opus-4-6" + const modelID = overrides.modelID ?? "claude-opus-4-7" const variant = "variant" in overrides ? overrides.variant : "max" const agentName = overrides.agentName ?? "sisyphus" const existingOptions = overrides.existingOptions ?? {} @@ -66,7 +71,7 @@ describe("createAnthropicEffortHook", () => { it("injects effort max for dotted opus ids", async () => { const hook = createAnthropicEffortHook() - const { input, output } = createMockParams({ modelID: "claude-opus-4.6" }) + const { input, output } = createMockParams({ modelID: "claude-opus-4.7" }) await hook["chat.params"](input, output) @@ -148,20 +153,36 @@ describe("createAnthropicEffortHook", () => { expect(output.options.effort).toBeUndefined() }) - it("#given github-copilot + claude model #then effort NOT injected", async () => { + it("#given github-copilot + claude opus model #then effort clamped to high (constrained provider)", async () => { // given const hook = createAnthropicEffortHook() const { input, output } = createMockParams({ providerID: "github-copilot", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", + }) + + // when + await hook["chat.params"](input, output) + + // then — github-copilot is a constrained provider, clamps max→high + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("#given github-copilot + claude sonnet model #then effort clamped to high", async () => { + // given + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ + providerID: "github-copilot", + modelID: "claude-sonnet-4-6", }) // when await hook["chat.params"](input, output) // then - expect(output.options.effort).toBeUndefined() - expect(input.message.variant).toBe("max") + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") }) describe("#given haiku models (effort unsupported)", () => { @@ -199,4 +220,92 @@ describe("createAnthropicEffortHook", () => { expect(output.options.effort).toBe("high") }) }) + + describe("#given anthropic OAuth auth (Claude Pro/Max) — regression for #3429", () => { + let tempDataDir: string + const originalXdgDataHome = process.env.XDG_DATA_HOME + + function writeAuthFile(providerEntries: Record>): void { + const opencodeDir = path.join(tempDataDir, "opencode") + mkdirSync(opencodeDir, { recursive: true }) + writeFileSync(path.join(opencodeDir, "auth.json"), JSON.stringify(providerEntries), "utf-8") + _resetProviderAuthCacheForTesting() + } + + beforeAll(() => { + tempDataDir = path.join(tmpdir(), `anthropic-effort-oauth-${Date.now()}-${Math.random().toString(36).slice(2)}`) + mkdirSync(tempDataDir, { recursive: true }) + process.env.XDG_DATA_HOME = tempDataDir + }) + + afterAll(() => { + if (originalXdgDataHome === undefined) { + delete process.env.XDG_DATA_HOME + } else { + process.env.XDG_DATA_HOME = originalXdgDataHome + } + rmSync(tempDataDir, { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + }) + + afterEach(() => { + _resetProviderAuthCacheForTesting() + }) + + it("clamps opus-4-6 + max to high when anthropic provider uses oauth", async () => { + // given an Anthropic OAuth session and variant=max on an Opus model + writeAuthFile({ anthropic: { type: "oauth" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-7" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then effort must be clamped to high so Anthropic's OAuth API accepts it + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("clamps dotted opus id + max to high under OAuth", async () => { + // given an Anthropic OAuth session and a dotted opus id + writeAuthFile({ anthropic: { type: "oauth" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4.7" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then effort must be clamped to high + expect(output.options.effort).toBe("high") + expect(input.message.variant).toBe("high") + }) + + it("still injects effort=max when anthropic auth is an API key", async () => { + // given an Anthropic API-key session (not OAuth) + writeAuthFile({ anthropic: { type: "api", key: "sk-ant-xxx" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-7" }) + + // when chat.params fires + await hook["chat.params"](input, output) + + // then API-key users keep the original max behaviour for Opus + expect(output.options.effort).toBe("max") + expect(input.message.variant).toBe("max") + }) + + it("does not clamp when OAuth belongs to a different provider", async () => { + // given OAuth entries for unrelated providers only + writeAuthFile({ "github-copilot": { type: "oauth" }, opencode: { type: "api", key: "sk-x" } }) + const hook = createAnthropicEffortHook() + const { input, output } = createMockParams({ modelID: "claude-opus-4-7", providerID: "anthropic" }) + + // when chat.params fires for the anthropic provider + await hook["chat.params"](input, output) + + // then max stays because anthropic itself is not OAuth + expect(output.options.effort).toBe("max") + expect(input.message.variant).toBe("max") + }) + }) }) diff --git a/src/hooks/atlas/AGENTS.md b/src/hooks/atlas/AGENTS.md index 21e4243fa..215e53861 100644 --- a/src/hooks/atlas/AGENTS.md +++ b/src/hooks/atlas/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/atlas/ — Master Boulder Orchestrator -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/atlas/compaction-agent-filter.test.ts b/src/hooks/atlas/compaction-agent-filter.test.ts index 790518e6c..b5a120f96 100644 --- a/src/hooks/atlas/compaction-agent-filter.test.ts +++ b/src/hooks/atlas/compaction-agent-filter.test.ts @@ -58,7 +58,7 @@ describe("atlas hook compaction agent filtering", () => { join(messageDir, fileName), JSON.stringify({ agent, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/final-wave-approval-gate-regression.test.ts b/src/hooks/atlas/final-wave-approval-gate-regression.test.ts index 180ab7cef..d0ce73c67 100644 --- a/src/hooks/atlas/final-wave-approval-gate-regression.test.ts +++ b/src/hooks/atlas/final-wave-approval-gate-regression.test.ts @@ -91,7 +91,7 @@ describe("Atlas final-wave approval gate regressions", () => { join(messageDirectory, "msg_test001.json"), JSON.stringify({ agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/final-wave-approval-gate.test.ts b/src/hooks/atlas/final-wave-approval-gate.test.ts index 717f66016..608a53235 100644 --- a/src/hooks/atlas/final-wave-approval-gate.test.ts +++ b/src/hooks/atlas/final-wave-approval-gate.test.ts @@ -99,7 +99,7 @@ describe("Atlas final verification approval gate", () => { join(messageDirectory, "msg_test001.json"), JSON.stringify({ agent: "atlas", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }), ) } diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index 0f9e7d605..a2e80cf78 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -79,7 +79,7 @@ describe("atlas hook", () => { } const messageData = { agent, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, } writeFileSync(join(messageDir, "msg_test001.json"), JSON.stringify(messageData)) } @@ -957,7 +957,8 @@ session_id: ses_untrusted_999 const updatedState = readBoulderState(TEST_DIR) expect(updatedState?.task_sessions?.["todo:1"]).toBeUndefined() expect(output.output).not.toContain('task(session_id="ses_untrusted_999"') - expect(output.output).toContain('task(session_id=""') + expect(output.output).not.toContain('task(task_id="ses_untrusted_999"') + expect(output.output).toContain('task(task_id=""') cleanupMessageStorage(sessionID) }) diff --git a/src/hooks/atlas/subagent-session-id.test.ts b/src/hooks/atlas/subagent-session-id.test.ts index b73a0c75c..3b8c68757 100644 --- a/src/hooks/atlas/subagent-session-id.test.ts +++ b/src/hooks/atlas/subagent-session-id.test.ts @@ -90,6 +90,17 @@ describe("extractSessionIdFromMetadata", () => { expect(result).toBe("ses_plugin_abc123") }) + test("extracts legacy session aliases from tool metadata object", () => { + // given + const metadata = { sessionID: "ses_plugin_alias_123" } + + // when + const result = extractSessionIdFromMetadata(metadata) + + // then + expect(result).toBe("ses_plugin_alias_123") + }) + test("returns undefined for metadata without sessionId", () => { // given const metadata = { title: "some task" } diff --git a/src/hooks/atlas/subagent-session-id.ts b/src/hooks/atlas/subagent-session-id.ts index 95aef2aee..cc52deb88 100644 --- a/src/hooks/atlas/subagent-session-id.ts +++ b/src/hooks/atlas/subagent-session-id.ts @@ -1,30 +1,20 @@ import type { PluginInput } from "@opencode-ai/plugin" +import { extractTaskLink } from "../../features/tool-metadata-store" import { log } from "../../shared/logger" import { isSessionInBoulderLineage } from "./boulder-session-lineage" import { HOOK_NAME } from "./hook-name" export function extractSessionIdFromMetadata(metadata: unknown): string | undefined { - if (metadata && typeof metadata === "object" && "sessionId" in metadata) { - const value = (metadata as Record).sessionId - if (typeof value === "string" && value.startsWith("ses_")) { - return value - } + const sessionId = extractTaskLink(metadata, "").sessionId + if (typeof sessionId === "string" && sessionId.startsWith("ses_")) { + return sessionId } + return undefined } export function extractSessionIdFromOutput(output: string): string | undefined { - const taskMetadataBlocks = [...output.matchAll(/([\s\S]*?)<\/task_metadata>/gi)] - const lastTaskMetadataBlock = taskMetadataBlocks.at(-1)?.[1] - if (lastTaskMetadataBlock) { - const taskMetadataSessionMatch = lastTaskMetadataBlock.match(/session_id:\s*(ses_[a-zA-Z0-9_-]+)/i) - if (taskMetadataSessionMatch) { - return taskMetadataSessionMatch[1] - } - } - - const explicitSessionMatches = [...output.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)] - return explicitSessionMatches.at(-1)?.[1] + return extractTaskLink(undefined, output).sessionId } export async function validateSubagentSessionId(input: { diff --git a/src/hooks/atlas/verification-reminders.ts b/src/hooks/atlas/verification-reminders.ts index b00618ecd..9bde55b9d 100644 --- a/src/hooks/atlas/verification-reminders.ts +++ b/src/hooks/atlas/verification-reminders.ts @@ -29,7 +29,7 @@ Your completion will NOT be recorded until you complete ALL of the following: If anything fails while closing this out, resume the same session immediately: \`\`\`typescript -task(session_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") +task(task_id="${sessionId}", load_skills=[], prompt="fix: checkbox not recorded correctly") \`\`\` **Your completion is NOT tracked until the checkbox is marked in the plan file.** @@ -47,7 +47,7 @@ ${VERIFICATION_REMINDER} **If ANY verification fails, use this immediately:** \`\`\` -task(session_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") +task(task_id="${sessionId}", load_skills=[], prompt="fix: [describe the specific failure]") \`\`\` ${buildReuseHint(sessionId)}` diff --git a/src/hooks/auto-slash-command/executor.test.ts b/src/hooks/auto-slash-command/executor.test.ts index 246557275..0fe169cb6 100644 --- a/src/hooks/auto-slash-command/executor.test.ts +++ b/src/hooks/auto-slash-command/executor.test.ts @@ -2,6 +2,7 @@ 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 { clearCommandLoaderCache } from "../../features/claude-code-command-loader" import { executeSlashCommand } from "./executor" const ENV_KEYS = [ @@ -95,6 +96,7 @@ describe("auto-slash command executor plugin dispatch", () => { let envSnapshot: EnvSnapshot beforeEach(() => { + clearCommandLoaderCache() tempDir = mkdtempSync(join(tmpdir(), "omo-executor-plugin-test-")) envSnapshot = { CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR, @@ -106,6 +108,7 @@ describe("auto-slash command executor plugin dispatch", () => { }) afterEach(() => { + clearCommandLoaderCache() for (const key of ENV_KEYS) { const previousValue = envSnapshot[key] if (previousValue === undefined) { diff --git a/src/hooks/auto-slash-command/index.test.ts b/src/hooks/auto-slash-command/index.test.ts index 543341b0b..cda63bf8c 100644 --- a/src/hooks/auto-slash-command/index.test.ts +++ b/src/hooks/auto-slash-command/index.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it, beforeEach, afterEach, spyOn, mock } from "bun:te import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" +import { clearCommandLoaderCache } from "../../features/claude-code-command-loader" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" import type { AutoSlashCommandHookInput, @@ -43,6 +44,7 @@ describe("createAutoSlashCommandHook", () => { let createAutoSlashCommandHook: AutoSlashCommandModule["createAutoSlashCommandHook"] beforeEach(async () => { + clearCommandLoaderCache() mock.restore() logCalls = [] spyOn(shared, "log").mockImplementation((message: string, data?: unknown) => { @@ -56,6 +58,7 @@ describe("createAutoSlashCommandHook", () => { }) afterEach(() => { + clearCommandLoaderCache() process.chdir(originalWorkingDirectory) rmSync(tempDir, { recursive: true, force: true }) mock.restore() diff --git a/src/hooks/auto-update-checker/hook.test.ts b/src/hooks/auto-update-checker/hook.test.ts new file mode 100644 index 000000000..a6cacd54d --- /dev/null +++ b/src/hooks/auto-update-checker/hook.test.ts @@ -0,0 +1,261 @@ +import type { PluginInput } from "@opencode-ai/plugin" +import { describe, expect, mock, test } from "bun:test" + +type CreateAutoUpdateCheckerHook = typeof import("./hook").createAutoUpdateCheckerHook +type HookOptions = Parameters[1] +type HookDeps = NonNullable[2]> + +let latestVersionCallCount = 0 +let scheduleDeferredStartupCheckCallCount = 0 + +const flushMicrotasks = async (count: number): Promise => { + for (let index = 0; index < count; index += 1) { + await Promise.resolve() + } +} + +const latestVersionMock = async () => { + latestVersionCallCount += 1 + return "3.0.1" +} + +const scheduleDeferredStartupCheckMock = (runCheck: () => void) => { + scheduleDeferredStartupCheckCallCount += 1 + scheduledCheck = runCheck +} + +let scheduledCheck: (() => void) | null = null + +mock.module("./checker/latest-version", () => ({ + getLatestVersion: latestVersionMock, +})) + +mock.module("./hook/deferred-startup-check", () => ({ + scheduleDeferredStartupCheck: scheduleDeferredStartupCheckMock, +})) + +const createPluginInput = (): PluginInput => ({ + client: {} as PluginInput["client"], + directory: "/tmp/project", + project: {} as PluginInput["project"], + worktree: "/tmp/project", + serverUrl: new URL("https://example.com"), + $: {} as PluginInput["$"], +} satisfies PluginInput) + +const createDeps = (overrides: Partial = {}) => { + const showConfigErrorsIfAny = mock(async () => undefined) + const updateAndShowConnectedProvidersCacheStatus = mock(async () => undefined) + const refreshModelCapabilitiesOnStartup = mock(async () => undefined) + const showModelCacheWarningIfNeeded = mock(async () => undefined) + const showLocalDevToast = mock(async () => undefined) + const showVersionToast = mock(async () => undefined) + const runBackgroundUpdateCheck = mock(async () => { + await latestVersionMock() + }) + + const deps: HookDeps = { + getCachedVersion: () => "3.0.0", + getLocalDevVersion: () => null, + showConfigErrorsIfAny, + updateAndShowConnectedProvidersCacheStatus, + refreshModelCapabilitiesOnStartup, + showModelCacheWarningIfNeeded, + showLocalDevToast, + showVersionToast, + runBackgroundUpdateCheck, + log: () => undefined, + ...overrides, + } + + return { + deps, + mocks: { + showConfigErrorsIfAny, + updateAndShowConnectedProvidersCacheStatus, + refreshModelCapabilitiesOnStartup, + showModelCacheWarningIfNeeded, + showLocalDevToast, + showVersionToast, + runBackgroundUpdateCheck, + }, + } +} + +const createHook = async ( + options: HookOptions = {}, + overrides: Partial = {}, +) => { + const module = await import("./hook") + const { deps, mocks } = createDeps(overrides) + + return { + hook: module.createAutoUpdateCheckerHook( + createPluginInput(), + { + showStartupToast: true, + autoUpdate: false, + ...options, + }, + deps, + ), + mocks, + } +} + +const resetDeferredState = (): void => { + latestVersionCallCount = 0 + scheduleDeferredStartupCheckCallCount = 0 + scheduledCheck = null +} + +const runScheduledCheck = async (): Promise => { + scheduledCheck?.() + await flushMicrotasks(8) +} + +const triggerSessionCreated = ( + hook: ReturnType, + properties?: { info?: { parentID?: string } }, +): void => { + hook.event({ event: { type: "session.created", properties } }) +} + +const triggerSessionIdle = (hook: ReturnType): void => { + hook.event({ event: { type: "session.idle" } }) +} + +describe("auto-update-checker hook", () => { + test("schedules deferred check on session.created without parentID", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionCreated(hook) + + // then + expect(scheduleDeferredStartupCheckCallCount).toBe(1) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + expect(latestVersionCallCount).toBe(0) + + // when + await runScheduledCheck() + + // then + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + expect(latestVersionCallCount).toBe(1) + }) + + test("does not schedule deferred check on session.created with parentID", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionCreated(hook, { info: { parentID: "parent-123" } }) + + // then + expect(scheduleDeferredStartupCheckCallCount).toBe(0) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + }) + + test("does not schedule deferred check on session.idle without session.created", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionIdle(hook) + + // then + expect(scheduleDeferredStartupCheckCallCount).toBe(0) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + }) + + test("runs all startup checks after deferred session.created check executes", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionCreated(hook) + await runScheduledCheck() + + // then + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.refreshModelCapabilitiesOnStartup).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + }) + + test("guards double execution across repeated session.created events", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook() + + // when + triggerSessionCreated(hook) + triggerSessionCreated(hook) + + // then + expect(scheduleDeferredStartupCheckCallCount).toBe(1) + + // when + await runScheduledCheck() + triggerSessionCreated(hook) + + // then + expect(scheduleDeferredStartupCheckCallCount).toBe(1) + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.runBackgroundUpdateCheck).toHaveBeenCalledTimes(1) + }) + + test("shows localDevToast when local dev version exists", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook({}, { + getLocalDevVersion: () => "3.0.0-dev", + }) + + // when + triggerSessionCreated(hook) + await runScheduledCheck() + + // then + expect(mocks.showConfigErrorsIfAny).toHaveBeenCalledTimes(1) + expect(mocks.updateAndShowConnectedProvidersCacheStatus).toHaveBeenCalledTimes(1) + expect(mocks.showModelCacheWarningIfNeeded).toHaveBeenCalledTimes(1) + expect(mocks.showLocalDevToast).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).not.toHaveBeenCalled() + expect(mocks.runBackgroundUpdateCheck).not.toHaveBeenCalled() + expect(latestVersionCallCount).toBe(0) + }) + + test("passes correct toast message with sisyphus enabled", async () => { + // given + resetDeferredState() + const { hook, mocks } = await createHook({ isSisyphusEnabled: true }) + + // when + triggerSessionCreated(hook) + await runScheduledCheck() + + // then + expect(mocks.showVersionToast).toHaveBeenCalledTimes(1) + expect(mocks.showVersionToast).toHaveBeenCalledWith( + expect.anything(), + "3.0.0", + expect.stringContaining("Sisyphus"), + ) + }) +}) diff --git a/src/hooks/auto-update-checker/hook.ts b/src/hooks/auto-update-checker/hook.ts index fbe3998da..2306c03a0 100644 --- a/src/hooks/auto-update-checker/hook.ts +++ b/src/hooks/auto-update-checker/hook.ts @@ -3,6 +3,7 @@ import { log } from "../../shared/logger" import type { AutoUpdateCheckerOptions } from "./types" import { getCachedVersion, getLocalDevVersion } from "./checker" import { runBackgroundUpdateCheck } from "./hook/background-update-check" +import { scheduleDeferredStartupCheck } from "./hook/deferred-startup-check" import { showConfigErrorsIfAny } from "./hook/config-errors-toast" import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status" import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status" @@ -35,6 +36,20 @@ const defaultDeps: AutoUpdateCheckerDeps = { log, } +const isRecord = (value: unknown): value is Record => { + return typeof value === "object" && value !== null +} + +const getParentID = (properties: unknown): string | undefined => { + if (!isRecord(properties)) return undefined + + const { info } = properties + if (!isRecord(info)) return undefined + + const { parentID } = info + return typeof parentID === "string" && parentID.length > 0 ? parentID : undefined +} + export function createAutoUpdateCheckerHook( ctx: PluginInput, options: AutoUpdateCheckerOptions = {}, @@ -60,44 +75,46 @@ export function createAutoUpdateCheckerHook( } let hasChecked = false + let hasScheduled = false return { event: ({ event }: { event: { type: string; properties?: unknown } }) => { if (event.type !== "session.created") return if (isCliRunMode) return - if (hasChecked) return + if (hasChecked || hasScheduled) return + if (getParentID(event.properties)) return - const props = event.properties as { info?: { parentID?: string } } | undefined - if (props?.info?.parentID) return + hasScheduled = true + scheduleDeferredStartupCheck(() => { hasChecked = true + void (async () => { + const cachedVersion = deps.getCachedVersion() + const localDevVersion = deps.getLocalDevVersion(ctx.directory) + const displayVersion = localDevVersion ?? cachedVersion - setTimeout(async () => { - const cachedVersion = deps.getCachedVersion() - const localDevVersion = deps.getLocalDevVersion(ctx.directory) - const displayVersion = localDevVersion ?? cachedVersion + await deps.showConfigErrorsIfAny(ctx) + await deps.updateAndShowConnectedProvidersCacheStatus(ctx) + await deps.refreshModelCapabilitiesOnStartup(modelCapabilities) + await deps.showModelCacheWarningIfNeeded(ctx) - await deps.showConfigErrorsIfAny(ctx) - await deps.updateAndShowConnectedProvidersCacheStatus(ctx) - await deps.refreshModelCapabilitiesOnStartup(modelCapabilities) - await deps.showModelCacheWarningIfNeeded(ctx) - - if (localDevVersion) { - if (showStartupToast) { - deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {}) + if (localDevVersion) { + if (showStartupToast) { + deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {}) + } + deps.log("[auto-update-checker] Local development mode") + return } - deps.log("[auto-update-checker] Local development mode") - return - } - if (showStartupToast) { - deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {}) - } + if (showStartupToast) { + deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {}) + } - deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => { - deps.log("[auto-update-checker] Background update check failed:", err) - }) - }, 0) + deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => { + deps.log("[auto-update-checker] Background update check failed:", err) + }) + })() + }) }, } } diff --git a/src/hooks/auto-update-checker/hook/deferred-startup-check.ts b/src/hooks/auto-update-checker/hook/deferred-startup-check.ts new file mode 100644 index 000000000..2e1066424 --- /dev/null +++ b/src/hooks/auto-update-checker/hook/deferred-startup-check.ts @@ -0,0 +1,4 @@ +export function scheduleDeferredStartupCheck(runCheck: () => void): void { + const timeout = setTimeout(runCheck, 5000) + timeout.unref?.() +} diff --git a/src/hooks/claude-code-hooks/AGENTS.md b/src/hooks/claude-code-hooks/AGENTS.md index 6055c4969..10a357756 100644 --- a/src/hooks/claude-code-hooks/AGENTS.md +++ b/src/hooks/claude-code-hooks/AGENTS.md @@ -1,6 +1,6 @@ # src/hooks/claude-code-hooks/ — Claude Code Compatibility -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/hooks/comment-checker/AGENTS.md b/src/hooks/comment-checker/AGENTS.md new file mode 100644 index 000000000..cc58f96dd --- /dev/null +++ b/src/hooks/comment-checker/AGENTS.md @@ -0,0 +1,62 @@ +# src/hooks/comment-checker/ — AI Slop Comment Blocker + +**Generated:** 2026-04-18 + +## OVERVIEW + +Tool Guard tier hook. Runs after `write`/`edit` tools to detect AI-generated comment patterns in code and block them before they land. Backed by `@code-yeongyu/comment-checker` binary (trusted dependency). + +## WHAT IT BLOCKS + +AI slop comment smells: +- Restating what code literally does (`// increment counter`) +- Filler phrases (`// obviously`, `// clearly`, `// simply`) +- Decorative separators without purpose +- JSDoc on trivially-named functions +- `// TODO:` without context +- Comments contradicting surrounding code + +See `@code-yeongyu/comment-checker` for the authoritative blocklist. + +## EXECUTION FLOW + +``` +tool.execute.after (write | edit | hashline edit) + → extract changed lines from tool output + → spawn comment-checker binary with changed file path + → parse findings (line ranges + violation category) + → if findings → inject tool-level error → agent must fix +``` + +## KEY FILES + +| File | Purpose | +|------|---------| +| `hook.ts` | `createCommentCheckerHook()` — main factory, tool.execute.after handler | +| `comment-checker-runner.ts` | Spawn binary, parse JSON output | +| `changed-line-extractor.ts` | Extract which lines changed from tool result | +| `findings-formatter.ts` | Format violations as actionable error message | +| `binary-resolver.ts` | Locate `comment-checker` binary (node_modules + PATH) | + +## CONFIG + +```jsonc +// oh-my-opencode.jsonc +{ + "comment_checker": { + "enabled": true, // default: true + "severity": "error" // error blocks, warning notifies only + } +} +``` + +Disable via `"disabled_hooks": ["comment-checker"]`. + +## BYPASS FOR LEGITIMATE COMMENTS + +Prefix with `// @allow` or mark file scope with `// comment-checker-disable-file` at top. Use sparingly — defeating the purpose. + +## RELATED + +- Doctor check: `src/cli/doctor/checks/tools.ts` verifies `comment-checker` binary availability +- Postinstall: `postinstall.mjs` downloads binary if missing diff --git a/src/hooks/comment-checker/hook.lazy-init.test.ts b/src/hooks/comment-checker/hook.lazy-init.test.ts new file mode 100644 index 000000000..2598aa3c6 --- /dev/null +++ b/src/hooks/comment-checker/hook.lazy-init.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it, mock, afterAll } from "bun:test" + +const startPendingCallCleanup = mock(() => {}) +const initializeCommentCheckerCli = mock(() => {}) + +mock.module("./cli-runner", () => ({ + initializeCommentCheckerCli, + getCommentCheckerCliPathPromise: () => Promise.resolve("/tmp/fake-comment-checker"), + isCliPathUsable: () => true, + processWithCli: async () => {}, + processApplyPatchEditsWithCli: async () => {}, +})) + +mock.module("./pending-calls", () => ({ + registerPendingCall: () => {}, + startPendingCallCleanup, + stopPendingCallCleanup: () => {}, + takePendingCall: () => undefined, +})) + +afterAll(() => { + mock.restore() +}) + +const { createCommentCheckerHooks } = await import("./hook") + +describe("comment-checker lazy initialization", () => { + it("initializes CLI and cleanup on first tool hook call only", async () => { + // given + const hooks = createCommentCheckerHooks() + const beforeHook = hooks["tool.execute.before"] + const input = { tool: "write", sessionID: "ses_test", callID: "call_test" } + const output = { args: { filePath: "src/a.ts" } } + + // when + expect(startPendingCallCleanup).toHaveBeenCalledTimes(0) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(0) + + // then + await beforeHook(input, output) + expect(startPendingCallCleanup).toHaveBeenCalledTimes(1) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(1) + + // when + await beforeHook(input, output) + + // then + expect(startPendingCallCleanup).toHaveBeenCalledTimes(1) + expect(initializeCommentCheckerCli).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/hooks/comment-checker/hook.ts b/src/hooks/comment-checker/hook.ts index 56632b1f9..089aca2e9 100644 --- a/src/hooks/comment-checker/hook.ts +++ b/src/hooks/comment-checker/hook.ts @@ -28,6 +28,7 @@ import { stopPendingCallCleanup, takePendingCall, } from "./pending-calls" +import { ensureCommentCheckerInitialization } from "./initialization-gate" import * as fs from "fs" import { tmpdir } from "os" @@ -48,14 +49,16 @@ function debugLog(...args: unknown[]) { export function createCommentCheckerHooks(config?: CommentCheckerConfig) { debugLog("createCommentCheckerHooks called", { config }) - startPendingCallCleanup() - initializeCommentCheckerCli(debugLog) - return { "tool.execute.before": async ( input: { tool: string; sessionID: string; callID: string }, output: { args: Record }, ): Promise => { + ensureCommentCheckerInitialization(() => { + startPendingCallCleanup() + initializeCommentCheckerCli(debugLog) + }) + debugLog("tool.execute.before:", { tool: input.tool, callID: input.callID, diff --git a/src/hooks/comment-checker/initialization-gate.ts b/src/hooks/comment-checker/initialization-gate.ts new file mode 100644 index 000000000..da9759a47 --- /dev/null +++ b/src/hooks/comment-checker/initialization-gate.ts @@ -0,0 +1,7 @@ +let initialized = false + +export function ensureCommentCheckerInitialization(initializer: () => void): void { + if (initialized) return + initialized = true + initializer() +} diff --git a/src/hooks/directory-agents-injector/finder.ts b/src/hooks/directory-agents-injector/finder.ts index 8ac8a1463..e04cfab74 100644 --- a/src/hooks/directory-agents-injector/finder.ts +++ b/src/hooks/directory-agents-injector/finder.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { constants, promises as fsPromises } from "node:fs"; import { dirname, isAbsolute, join, resolve } from "node:path"; import { AGENTS_FILENAME } from "./constants"; @@ -9,10 +9,10 @@ export function resolveFilePath(rootDirectory: string, path: string): string | n return resolve(rootDirectory, path); } -export function findAgentsMdUp(input: { +export async function findAgentsMdUp(input: { startDir: string; rootDir: string; -}): string[] { +}): Promise { const found: string[] = []; let current = input.startDir; @@ -22,7 +22,11 @@ export function findAgentsMdUp(input: { const isRootDir = current === input.rootDir; if (!isRootDir) { const agentsPath = join(current, AGENTS_FILENAME); - if (existsSync(agentsPath)) { + const exists = await fsPromises + .access(agentsPath, constants.F_OK) + .then(() => true) + .catch(() => false); + if (exists) { found.push(agentsPath); } } diff --git a/src/hooks/directory-agents-injector/injector.test.ts b/src/hooks/directory-agents-injector/injector.test.ts index 8f5701645..822381a69 100644 --- a/src/hooks/directory-agents-injector/injector.test.ts +++ b/src/hooks/directory-agents-injector/injector.test.ts @@ -84,6 +84,23 @@ describe("processFilePathForAgentsInjection", () => { expect(output.output).toContain(srcAgentsContent) }) + it("finds AGENTS.md files while walking up directories", async () => { + // given + const { findAgentsMdUp } = await import("./finder") + + // when + const agentsPaths = await findAgentsMdUp({ + startDir: componentsDirectory, + rootDir: testRoot, + }) + + // then + expect(agentsPaths).toEqual([ + join(srcDirectory, "AGENTS.md"), + join(componentsDirectory, "AGENTS.md"), + ]) + }) + it("skips root-level AGENTS.md", async () => { // given rmSync(join(srcDirectory, "AGENTS.md"), { force: true }) diff --git a/src/hooks/directory-agents-injector/injector.ts b/src/hooks/directory-agents-injector/injector.ts index 28d0be943..3ff40784d 100644 --- a/src/hooks/directory-agents-injector/injector.ts +++ b/src/hooks/directory-agents-injector/injector.ts @@ -1,5 +1,5 @@ import type { PluginInput } from "@opencode-ai/plugin"; -import { readFileSync } from "node:fs"; +import { promises as fsPromises } from "node:fs"; import { dirname } from "node:path"; import type { createDynamicTruncator } from "../../shared/dynamic-truncator"; @@ -31,7 +31,7 @@ export async function processFilePathForAgentsInjection(input: { const dir = dirname(resolved); const cache = getSessionCache(input.sessionCaches, input.sessionID); - const agentsPaths = findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); + const agentsPaths = await findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); let dirty = false; for (const agentsPath of agentsPaths) { @@ -39,7 +39,8 @@ export async function processFilePathForAgentsInjection(input: { if (cache.has(agentsDir)) continue; try { - const content = readFileSync(agentsPath, "utf-8"); + const content = await fsPromises.readFile(agentsPath, "utf-8"); + cache.add(agentsDir); const { result, truncated } = await input.truncator.truncate( input.sessionID, content, @@ -48,7 +49,6 @@ export async function processFilePathForAgentsInjection(input: { ? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${agentsPath}]` : ""; input.output.output += `\n\n[Directory Context: ${agentsPath}]\n${result}${truncationNotice}`; - cache.add(agentsDir); dirty = true; } catch {} } diff --git a/src/hooks/directory-readme-injector/finder.ts b/src/hooks/directory-readme-injector/finder.ts index 70e0ba04d..904ef000c 100644 --- a/src/hooks/directory-readme-injector/finder.ts +++ b/src/hooks/directory-readme-injector/finder.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { access } from "node:fs/promises"; import { dirname, isAbsolute, join, resolve } from "node:path"; import { README_FILENAME } from "./constants"; @@ -9,17 +9,19 @@ export function resolveFilePath(rootDirectory: string, path: string): string | n return resolve(rootDirectory, path); } -export function findReadmeMdUp(input: { +export async function findReadmeMdUp(input: { startDir: string; rootDir: string; -}): string[] { +}): Promise { const found: string[] = []; let current = input.startDir; while (true) { const readmePath = join(current, README_FILENAME); - if (existsSync(readmePath)) { + try { + await access(readmePath); found.push(readmePath); + } catch { } if (current === input.rootDir) break; diff --git a/src/hooks/directory-readme-injector/injector.test.ts b/src/hooks/directory-readme-injector/injector.test.ts index 74294fd7c..c8e704121 100644 --- a/src/hooks/directory-readme-injector/injector.test.ts +++ b/src/hooks/directory-readme-injector/injector.test.ts @@ -133,6 +133,32 @@ describe("processFilePathForReadmeInjection", () => { expect(output.output).toContain("# Components README") }) + it("returns a promise and finds README.md files from temp fixtures", async () => { + // given + const sourceDirectory = join(testRoot, "src") + const componentsDirectory = join(sourceDirectory, "components") + mkdirSync(componentsDirectory, { recursive: true }) + writeFileSync(join(testRoot, "README.md"), "# Root README") + writeFileSync(join(sourceDirectory, "README.md"), "# Src README") + writeFileSync(join(componentsDirectory, "README.md"), "# Components README") + + const { findReadmeMdUp } = await import("./finder") + + // when + const promise = findReadmeMdUp({ + startDir: componentsDirectory, + rootDir: testRoot, + }) + + // then + expect(promise).toBeInstanceOf(Promise) + await expect(promise).resolves.toEqual([ + join(testRoot, "README.md"), + join(sourceDirectory, "README.md"), + join(componentsDirectory, "README.md"), + ]) + }) + it("does not re-inject already cached directories", async () => { // given const sourceDirectory = join(testRoot, "src") diff --git a/src/hooks/directory-readme-injector/injector.ts b/src/hooks/directory-readme-injector/injector.ts index bfeae7d44..ce3ff7212 100644 --- a/src/hooks/directory-readme-injector/injector.ts +++ b/src/hooks/directory-readme-injector/injector.ts @@ -1,5 +1,5 @@ import type { PluginInput } from "@opencode-ai/plugin"; -import { readFileSync } from "node:fs"; +import { readFile } from "node:fs/promises"; import { dirname } from "node:path"; import type { createDynamicTruncator } from "../../shared/dynamic-truncator"; @@ -31,7 +31,7 @@ export async function processFilePathForReadmeInjection(input: { const dir = dirname(resolved); const cache = getSessionCache(input.sessionCaches, input.sessionID); - const readmePaths = findReadmeMdUp({ startDir: dir, rootDir: input.ctx.directory }); + const readmePaths = await findReadmeMdUp({ startDir: dir, rootDir: input.ctx.directory }); let dirty = false; for (const readmePath of readmePaths) { @@ -39,7 +39,7 @@ export async function processFilePathForReadmeInjection(input: { if (cache.has(readmeDir)) continue; try { - const content = readFileSync(readmePath, "utf-8"); + const content = await readFile(readmePath, "utf-8"); const { result, truncated } = await input.truncator.truncate( input.sessionID, content, diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 051cbd12a..8fd15af2f 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -14,7 +14,13 @@ export { createEmptyTaskResponseDetectorHook } from "./empty-task-response-detec export { createAnthropicContextWindowLimitRecoveryHook, type AnthropicContextWindowLimitRecoveryOptions } from "./anthropic-context-window-limit-recovery"; export { createThinkModeHook } from "./think-mode"; -export { createModelFallbackHook, setPendingModelFallback, clearPendingModelFallback, type ModelFallbackState } from "./model-fallback/hook"; +export { + createModelFallbackHook, + setPendingModelFallback, + clearPendingModelFallback, + type ModelFallbackHook, + type ModelFallbackState, +} from "./model-fallback/hook"; export { createClaudeCodeHooksHook } from "./claude-code-hooks"; export { createRulesInjectorHook } from "./rules-injector"; export { createBackgroundNotificationHook } from "./background-notification" diff --git a/src/hooks/keyword-detector/ultrawork/default.ts b/src/hooks/keyword-detector/ultrawork/default.ts index 37790d9ea..0c95c5f1e 100644 --- a/src/hooks/keyword-detector/ultrawork/default.ts +++ b/src/hooks/keyword-detector/ultrawork/default.ts @@ -115,15 +115,15 @@ task(subagent_type="plan", load_skills=[], run_in_background=false, prompt=" void + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void +} + +export function createModelFallbackControllerAccessor(): ModelFallbackControllerAccessor { + let controller: ModelFallbackStateController | null = null + + function register(nextController: ModelFallbackStateController): void { + controller = nextController + } + + function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { + controller?.setSessionFallbackChain(sessionID, fallbackChain) + } + + function clearSessionFallbackChain(sessionID: string): void { + controller?.clearSessionFallbackChain(sessionID) + } + + return { + register, + setSessionFallbackChain, + clearSessionFallbackChain, + } +} diff --git a/src/hooks/model-fallback/fallback-state-controller.ts b/src/hooks/model-fallback/fallback-state-controller.ts new file mode 100644 index 000000000..4230bfb0a --- /dev/null +++ b/src/hooks/model-fallback/fallback-state-controller.ts @@ -0,0 +1,134 @@ +import type { FallbackEntry } from "../../shared/model-requirements" +import { getAgentConfigKey } from "../../shared/agent-display-names" +import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements" +import { log } from "../../shared/logger" +import { getNextReachableFallback } from "./next-fallback" + +type ModelFallbackStateLike = { + providerID: string + modelID: string + fallbackChain: FallbackEntry[] + attemptCount: number + pending: boolean +} + +export type ModelFallbackStateController = { + lastToastKey: Map + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void + setPendingModelFallback: ( + sessionID: string, + agentName: string, + currentProviderID: string, + currentModelID: string, + ) => boolean + getNextFallback: (sessionID: string) => ReturnType + clearPendingModelFallback: (sessionID: string) => void + hasPendingModelFallback: (sessionID: string) => boolean + getFallbackState: (sessionID: string) => ModelFallbackStateLike | undefined + reset: () => void +} + +export function createModelFallbackStateController(input: { + pendingModelFallbacks: Map + lastToastKey: Map + sessionFallbackChains: Map +}): ModelFallbackStateController { + const { pendingModelFallbacks, lastToastKey, sessionFallbackChains } = input + + function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { + if (!sessionID) return + sessionFallbackChains.set(sessionID, fallbackChain?.length ? fallbackChain : []) + } + + function clearSessionFallbackChain(sessionID: string): void { + sessionFallbackChains.delete(sessionID) + } + + function setPendingModelFallback( + sessionID: string, + agentName: string, + currentProviderID: string, + currentModelID: string, + ): boolean { + const agentKey = getAgentConfigKey(agentName) + const requirements = AGENT_MODEL_REQUIREMENTS[agentKey] + const fallbackChain = sessionFallbackChains.get(sessionID) ?? requirements?.fallbackChain + + if (!fallbackChain?.length) { + log("[model-fallback] No fallback chain for agent: " + agentName + " (key: " + agentKey + ")") + return false + } + + const existing = pendingModelFallbacks.get(sessionID) + if (!existing) { + pendingModelFallbacks.set(sessionID, { + providerID: currentProviderID, + modelID: currentModelID, + fallbackChain, + attemptCount: 0, + pending: true, + }) + log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) + return true + } + + if (existing.pending) { + log("[model-fallback] Pending fallback already armed for session: " + sessionID) + return false + } + + existing.providerID = currentProviderID + existing.modelID = currentModelID + existing.pending = true + if (existing.attemptCount >= existing.fallbackChain.length) { + log("[model-fallback] Fallback chain exhausted for session: " + sessionID) + return false + } + log("[model-fallback] Re-armed pending fallback for session: " + sessionID) + return true + } + + function getNextFallback(sessionID: string): ReturnType { + const state = pendingModelFallbacks.get(sessionID) + if (!state?.pending) return null + + const fallback = getNextReachableFallback(sessionID, state) + if (fallback) return fallback + + log("[model-fallback] No more fallbacks for session: " + sessionID) + pendingModelFallbacks.delete(sessionID) + return null + } + + function clearPendingModelFallback(sessionID: string): void { + pendingModelFallbacks.delete(sessionID) + lastToastKey.delete(sessionID) + } + + function hasPendingModelFallback(sessionID: string): boolean { + return pendingModelFallbacks.get(sessionID)?.pending === true + } + + function getFallbackState(sessionID: string): ModelFallbackStateLike | undefined { + return pendingModelFallbacks.get(sessionID) + } + + function reset(): void { + pendingModelFallbacks.clear() + lastToastKey.clear() + sessionFallbackChains.clear() + } + + return { + lastToastKey, + setSessionFallbackChain, + clearSessionFallbackChain, + setPendingModelFallback, + getNextFallback, + clearPendingModelFallback, + hasPendingModelFallback, + getFallbackState, + reset, + } +} diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 637503356..de9e66fd7 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -24,7 +24,7 @@ const selectFallbackProviderMock = mock((providers: string[], preferredProviderI const transformModelForProviderMock = mock((provider: string, model: string) => { if (provider === "github-copilot") { return model - .replace("claude-opus-4-6", "claude-opus-4.6") + .replace("claude-opus-4-7", "claude-opus-4.7") .replace("claude-sonnet-4-6", "claude-sonnet-4.6") .replace("claude-sonnet-4-5", "claude-sonnet-4.5") .replace("claude-haiku-4-5", "claude-haiku-4.5") @@ -70,22 +70,23 @@ const { setPendingModelFallback, } = await importFreshModelFallbackHookModule() +type ModelFallbackHook = ReturnType + describe("model fallback hook", () => { + let modelFallback: ModelFallbackHook + beforeEach(() => { + modelFallback = createModelFallbackHook() readConnectedProvidersCacheMock.mockReturnValue(null) readProviderModelsCacheMock.mockReturnValue(null) readConnectedProvidersCacheMock.mockClear() readProviderModelsCacheMock.mockClear() selectFallbackProviderMock.mockClear() - - clearPendingModelFallback("ses_model_fallback_main") - clearPendingModelFallback("ses_model_fallback_ghcp") - clearPendingModelFallback("ses_model_fallback_google") }) test("applies pending fallback on chat.message by overriding model", async () => { //#given - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -93,16 +94,17 @@ describe("model fallback hook", () => { } const set = setPendingModelFallback( + modelFallback, "ses_model_fallback_main", "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) expect(set).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -117,13 +119,13 @@ describe("model fallback hook", () => { //#then expect(output.message["model"]).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }) test("preserves fallback progression across repeated session.error retries", async () => { //#given - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -132,12 +134,12 @@ describe("model fallback hook", () => { const sessionID = "ses_model_fallback_main" expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking"), + setPendingModelFallback(modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7-thinking"), ).toBe(true) const firstOutput = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -149,17 +151,17 @@ describe("model fallback hook", () => { //#then expect(firstOutput.message["model"]).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) //#when - second error re-arms fallback and should advance to next entry expect( - setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6"), + setPendingModelFallback(modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-7"), ).toBe(true) const secondOutput = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, parts: [{ type: "text", text: "continue" }], } @@ -176,57 +178,60 @@ describe("model fallback hook", () => { test("does not re-arm fallback when one is already pending", () => { //#given const sessionID = "ses_model_fallback_pending_guard" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) //#when const firstSet = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) const secondSet = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) //#then expect(firstSet).toBe(true) expect(secondSet).toBe(false) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("skips no-op fallback entries that resolve to same provider/model", async () => { //#given const sessionID = "ses_model_fallback_noop_skip" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + setSessionFallbackChain(modelFallback, sessionID, [ + { providers: ["anthropic"], model: "claude-opus-4-7" }, { providers: ["opencode"], model: "kimi-k2.5-free" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6", + "claude-opus-4-7", ), ).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, parts: [{ type: "text", text: "continue" }], } @@ -239,38 +244,39 @@ describe("model fallback hook", () => { providerID: "opencode", modelID: "kimi-k2.5-free", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("skips no-op fallback entries even when variant differs", async () => { //#given const sessionID = "ses_model_fallback_noop_variant_skip" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ - { providers: ["quotio"], model: "claude-opus-4-6", variant: "max" }, + setSessionFallbackChain(modelFallback, sessionID, [ + { providers: ["quotio"], model: "claude-opus-4-7", variant: "max" }, { providers: ["quotio"], model: "gpt-5.2" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "quotio", - "claude-opus-4-6", + "claude-opus-4-7", ), ).toBe(true) const output = { message: { - model: { providerID: "quotio", modelID: "claude-opus-4-6" }, + model: { providerID: "quotio", modelID: "claude-opus-4-7" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -285,28 +291,29 @@ describe("model fallback hook", () => { modelID: "gpt-5.2", }) expect(output.message["variant"]).toBeUndefined() - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("uses connected preferred provider when fallback entry providers are disconnected", async () => { //#given const sessionID = "ses_model_fallback_preferred_provider" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) readConnectedProvidersCacheMock.mockReturnValue(["provider-x"]) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, ) => Promise } - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["provider-y"], model: "fallback-model" }, ]) expect( setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Ultraworker", "provider-x", @@ -329,17 +336,18 @@ describe("model fallback hook", () => { providerID: "provider-x", modelID: "fallback-model", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("does not fall back to hardcoded agent chain when session explicitly stores no fallback chain [regression #2941]", () => { //#given const sessionID = "ses_model_fallback_explicit_none" - clearPendingModelFallback(sessionID) - setSessionFallbackChain(sessionID, undefined) + clearPendingModelFallback(modelFallback, sessionID) + setSessionFallbackChain(modelFallback, sessionID, undefined) //#when const set = setPendingModelFallback( + modelFallback, sessionID, "Sisyphus - Junior", "anthropic", @@ -348,7 +356,7 @@ describe("model fallback hook", () => { //#then expect(set).toBe(false) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("shows toast when fallback is applied", async () => { @@ -366,16 +374,17 @@ describe("model fallback hook", () => { } const set = setPendingModelFallback( + hook, "ses_model_fallback_toast", "Sisyphus - Ultraworker", "anthropic", - "claude-opus-4-6-thinking", + "claude-opus-4-7-thinking", ) expect(set).toBe(true) const output = { message: { - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, variant: "max", }, parts: [{ type: "text", text: "continue" }], @@ -392,9 +401,9 @@ describe("model fallback hook", () => { test("transforms model names for github-copilot provider via fallback chain", async () => { //#given const sessionID = "ses_model_fallback_ghcp" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -402,11 +411,12 @@ describe("model fallback hook", () => { } // Set a custom fallback chain that routes through github-copilot - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["github-copilot"], model: "claude-sonnet-4-6" }, ]) const set = setPendingModelFallback( + modelFallback, sessionID, "Atlas - Plan Executor", "github-copilot", @@ -430,15 +440,15 @@ describe("model fallback hook", () => { modelID: "claude-sonnet-4.6", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) test("preserves canonical google preview model names via fallback chain", async () => { //#given const sessionID = "ses_model_fallback_google" - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) - const hook = createModelFallbackHook() as unknown as { + const hook = modelFallback as unknown as { "chat.message"?: ( input: { sessionID: string }, output: { message: Record; parts: Array<{ type: string; text?: string }> }, @@ -446,11 +456,12 @@ describe("model fallback hook", () => { } // Set a custom fallback chain that routes through google - setSessionFallbackChain(sessionID, [ + setSessionFallbackChain(modelFallback, sessionID, [ { providers: ["google"], model: "gemini-3.1-pro-preview" }, ]) const set = setPendingModelFallback( + modelFallback, sessionID, "Oracle", "google", @@ -474,7 +485,7 @@ describe("model fallback hook", () => { modelID: "gemini-3.1-pro-preview", }) - clearPendingModelFallback(sessionID) + clearPendingModelFallback(modelFallback, sessionID) }) }) diff --git a/src/hooks/model-fallback/hook.ts b/src/hooks/model-fallback/hook.ts index b188bd48d..fee130ed8 100644 --- a/src/hooks/model-fallback/hook.ts +++ b/src/hooks/model-fallback/hook.ts @@ -1,13 +1,11 @@ import type { FallbackEntry } from "../../shared/model-requirements" -import { getAgentConfigKey } from "../../shared/agent-display-names" -import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements" -import { readConnectedProvidersCache, readProviderModelsCache } from "../../shared/connected-providers-cache" -import { selectFallbackProvider } from "../../shared/model-error-classifier" -import { transformModelForProvider } from "../../shared/provider-model-id-transform" -import { log } from "../../shared/logger" import type { ChatMessageInput, ChatMessageHandlerOutput } from "../../plugin/chat-message" import { applyFallbackToChatMessage } from "./chat-message-fallback-handler" -import { getNextReachableFallback } from "./next-fallback" +import { + createModelFallbackStateController, + type ModelFallbackStateController, +} from "./fallback-state-controller" +import type { ModelFallbackControllerAccessor } from "./controller-accessor" type FallbackToast = (input: { title: string @@ -31,30 +29,45 @@ export type ModelFallbackState = { pending: boolean } -/** - * Map of sessionID -> pending model fallback state - * When a model error occurs, we store the fallback info here. - * The next chat.message call will use this to switch to the fallback model. - */ -const pendingModelFallbacks = new Map() -const lastToastKey = new Map() -const sessionFallbackChains = new Map() +type ModelFallbackControllerWithState = Pick< + ModelFallbackStateController, + | "lastToastKey" + | "setSessionFallbackChain" + | "clearSessionFallbackChain" + | "setPendingModelFallback" + | "getNextFallback" + | "clearPendingModelFallback" + | "hasPendingModelFallback" + | "getFallbackState" + | "reset" +> -export function setSessionFallbackChain(sessionID: string, fallbackChain: FallbackEntry[] | undefined): void { - if (!sessionID) return - if (!fallbackChain) { - sessionFallbackChains.set(sessionID, []) - return - } - if (fallbackChain.length === 0) { - sessionFallbackChains.set(sessionID, []) - return - } - sessionFallbackChains.set(sessionID, fallbackChain) +export type ModelFallbackHook = ModelFallbackControllerWithState & { + "chat.message": ( + input: ChatMessageInput, + output: ChatMessageHandlerOutput, + ) => Promise } -export function clearSessionFallbackChain(sessionID: string): void { - sessionFallbackChains.delete(sessionID) +type ModelFallbackHookArgs = { + toast?: FallbackToast + onApplied?: FallbackCallback + controllerAccessor?: ModelFallbackControllerAccessor +} + +export function setSessionFallbackChain( + controller: Pick, + sessionID: string, + fallbackChain: FallbackEntry[] | undefined, +): void { + controller.setSessionFallbackChain(sessionID, fallbackChain) +} + +export function clearSessionFallbackChain( + controller: Pick, + sessionID: string, +): void { + controller.clearSessionFallbackChain(sessionID) } /** @@ -62,56 +75,18 @@ export function clearSessionFallbackChain(sessionID: string): void { * Called when a model error is detected in session.error handler. */ export function setPendingModelFallback( + controller: Pick, sessionID: string, agentName: string, currentProviderID: string, currentModelID: string, ): boolean { - const agentKey = getAgentConfigKey(agentName) - const requirements = AGENT_MODEL_REQUIREMENTS[agentKey] - const hasSessionFallback = sessionFallbackChains.has(sessionID) - const sessionFallback = sessionFallbackChains.get(sessionID) - const fallbackChain = hasSessionFallback - ? sessionFallback - : requirements?.fallbackChain - - if (!fallbackChain || fallbackChain.length === 0) { - log("[model-fallback] No fallback chain for agent: " + agentName + " (key: " + agentKey + ")") - return false - } - - const existing = pendingModelFallbacks.get(sessionID) - - if (existing) { - if (existing.pending) { - log("[model-fallback] Pending fallback already armed for session: " + sessionID) - return false - } - - // Preserve progression across repeated session.error retries in same session. - // We only mark the next turn as pending fallback application. - existing.providerID = currentProviderID - existing.modelID = currentModelID - existing.pending = true - if (existing.attemptCount >= existing.fallbackChain.length) { - log("[model-fallback] Fallback chain exhausted for session: " + sessionID) - return false - } - log("[model-fallback] Re-armed pending fallback for session: " + sessionID) - return true - } - - const state: ModelFallbackState = { - providerID: currentProviderID, - modelID: currentModelID, - fallbackChain, - attemptCount: 0, - pending: true, - } - - pendingModelFallbacks.set(sessionID, state) - log("[model-fallback] Set pending fallback for session: " + sessionID + ", agent: " + agentName) - return true + return controller.setPendingModelFallback( + sessionID, + agentName, + currentProviderID, + currentModelID, + ) } /** @@ -119,55 +94,71 @@ export function setPendingModelFallback( * Increments attemptCount each time called. */ export function getNextFallback( + controller: Pick, sessionID: string, ): { providerID: string; modelID: string; variant?: string } | null { - const state = pendingModelFallbacks.get(sessionID) - if (!state) return null - - if (!state.pending) return null - - const fallback = getNextReachableFallback(sessionID, state) - if (fallback) { - return fallback - } - - log("[model-fallback] No more fallbacks for session: " + sessionID) - pendingModelFallbacks.delete(sessionID) - return null + return controller.getNextFallback(sessionID) } /** * Clears the pending fallback for a session. * Called after fallback is successfully applied. */ -export function clearPendingModelFallback(sessionID: string): void { - pendingModelFallbacks.delete(sessionID) - lastToastKey.delete(sessionID) +export function clearPendingModelFallback( + controller: Pick, + sessionID: string, +): void { + controller.clearPendingModelFallback(sessionID) } /** * Checks if there's a pending fallback for a session. */ -export function hasPendingModelFallback(sessionID: string): boolean { - const state = pendingModelFallbacks.get(sessionID) - return state?.pending === true +export function hasPendingModelFallback( + controller: Pick, + sessionID: string, +): boolean { + return controller.hasPendingModelFallback(sessionID) } /** * Gets the current fallback state for a session (for debugging). */ -export function getFallbackState(sessionID: string): ModelFallbackState | undefined { - return pendingModelFallbacks.get(sessionID) +export function getFallbackState( + controller: Pick, + sessionID: string, +): ModelFallbackState | undefined { + return controller.getFallbackState(sessionID) } /** * Creates a chat.message hook that applies model fallbacks when pending. */ -export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplied?: FallbackCallback }) { +export function createModelFallbackHook(args?: ModelFallbackHookArgs): ModelFallbackHook { + const pendingModelFallbacks = new Map() + const lastToastKey = new Map() + const sessionFallbackChains = new Map() + const controller = createModelFallbackStateController({ + pendingModelFallbacks, + lastToastKey, + sessionFallbackChains, + }) + + args?.controllerAccessor?.register(controller) + const toast = args?.toast const onApplied = args?.onApplied return { + lastToastKey: controller.lastToastKey, + setSessionFallbackChain: controller.setSessionFallbackChain, + clearSessionFallbackChain: controller.clearSessionFallbackChain, + setPendingModelFallback: controller.setPendingModelFallback, + getNextFallback: controller.getNextFallback, + clearPendingModelFallback: controller.clearPendingModelFallback, + hasPendingModelFallback: controller.hasPendingModelFallback, + getFallbackState: controller.getFallbackState, + reset: controller.reset, "chat.message": async ( input: ChatMessageInput, output: ChatMessageHandlerOutput, @@ -175,7 +166,7 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie const { sessionID } = input if (!sessionID) return - const fallback = getNextFallback(sessionID) + const fallback = getNextFallback(controller, sessionID) if (!fallback) return await applyFallbackToChatMessage({ @@ -184,18 +175,15 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie fallback, toast, onApplied, - lastToastKey, + lastToastKey: controller.lastToastKey, }) }, } } /** - * Resets all module-global state for testing. - * Clears pending fallbacks, toast keys, and session chains. + * Resets hook-owned state for testing. */ -export function _resetForTesting(): void { - pendingModelFallbacks.clear() - lastToastKey.clear() - sessionFallbackChains.clear() +export function _resetForTesting(controller?: Pick): void { + controller?.reset() } diff --git a/src/hooks/model-fallback/index.ts b/src/hooks/model-fallback/index.ts new file mode 100644 index 000000000..08e4c0dd7 --- /dev/null +++ b/src/hooks/model-fallback/index.ts @@ -0,0 +1,2 @@ +export { createModelFallbackControllerAccessor } from "./controller-accessor" +export type { ModelFallbackControllerAccessor } from "./controller-accessor" diff --git a/src/hooks/no-hephaestus-non-gpt/index.test.ts b/src/hooks/no-hephaestus-non-gpt/index.test.ts index 7686bdbf1..6ca505f3c 100644 --- a/src/hooks/no-hephaestus-non-gpt/index.test.ts +++ b/src/hooks/no-hephaestus-non-gpt/index.test.ts @@ -30,12 +30,12 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_1", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output1) await hook["chat.message"]?.({ sessionID: "ses_1", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output2) // then - toast is shown and agent is switched to sisyphus @@ -66,7 +66,7 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_opt_out", agent: HEPHAESTUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - warning toast is shown but agent is not switched @@ -114,7 +114,7 @@ describe("no-hephaestus-non-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_3", agent: SISYPHUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - no toast @@ -136,7 +136,7 @@ describe("no-hephaestus-non-gpt hook", () => { // when - chat.message runs without input.agent await hook["chat.message"]?.({ sessionID: "ses_4", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - toast shown via session-agent fallback, switched to sisyphus diff --git a/src/hooks/no-sisyphus-gpt/index.test.ts b/src/hooks/no-sisyphus-gpt/index.test.ts index 908a01351..baeb23722 100644 --- a/src/hooks/no-sisyphus-gpt/index.test.ts +++ b/src/hooks/no-sisyphus-gpt/index.test.ts @@ -83,7 +83,7 @@ describe("no-sisyphus-gpt hook", () => { await hook["chat.message"]?.({ sessionID: "ses_2", agent: SISYPHUS_DISPLAY, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, output) // then - no toast diff --git a/src/hooks/preemptive-compaction-trigger.ts b/src/hooks/preemptive-compaction-trigger.ts new file mode 100644 index 000000000..bbab74f76 --- /dev/null +++ b/src/hooks/preemptive-compaction-trigger.ts @@ -0,0 +1,131 @@ +import type { OhMyOpenCodeConfig } from "../config" +import { + resolveActualContextLimit, + type ContextLimitModelCacheState, +} from "../shared/context-limit-resolver" +import { log } from "../shared/logger" + +import { resolveCompactionModel } from "./shared/compaction-model-resolver" +import type { + CachedCompactionState, + PreemptiveCompactionContext, +} from "./preemptive-compaction-types" + +const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 60_000 +const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78 +const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000 + +declare function setTimeout(handler: () => void, timeout?: number): unknown +declare function clearTimeout(timeoutID: unknown): void + +async function withTimeout( + promise: Promise, + timeoutMs: number, + errorMessage: string, +): Promise { + let timeoutID: unknown + + const timeoutPromise = new Promise((_, reject) => { + timeoutID = setTimeout(() => { + reject(new Error(errorMessage)) + }, timeoutMs) + }) + + return await Promise.race([promise, timeoutPromise]).finally(() => { + clearTimeout(timeoutID) + }) +} + +export async function runPreemptiveCompactionIfNeeded(args: { + ctx: PreemptiveCompactionContext + pluginConfig: OhMyOpenCodeConfig + modelCacheState?: ContextLimitModelCacheState + sessionID: string + tokenCache: Map + compactionInProgress: Set + compactedSessions: Set + lastCompactionTime: Map +}): Promise { + const { + ctx, + pluginConfig, + modelCacheState, + sessionID, + tokenCache, + compactionInProgress, + compactedSessions, + lastCompactionTime, + } = args + + if (compactedSessions.has(sessionID) || compactionInProgress.has(sessionID)) return + + const lastTime = lastCompactionTime.get(sessionID) + if (lastTime && Date.now() - lastTime < PREEMPTIVE_COMPACTION_COOLDOWN_MS) return + + const cached = tokenCache.get(sessionID) + if (!cached) return + + const actualLimit = resolveActualContextLimit( + cached.providerID, + cached.modelID, + modelCacheState, + ) + + if (actualLimit === null) { + log("[preemptive-compaction] Skipping preemptive compaction: unknown context limit for model", { + providerID: cached.providerID, + modelID: cached.modelID, + }) + return + } + + const totalInputTokens = (cached.tokens.input ?? 0) + (cached.tokens.cache?.read ?? 0) + const usageRatio = totalInputTokens / actualLimit + if (usageRatio < PREEMPTIVE_COMPACTION_THRESHOLD || !cached.modelID) return + + compactionInProgress.add(sessionID) + lastCompactionTime.set(sessionID, Date.now()) + + try { + const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel( + pluginConfig, + sessionID, + cached.providerID, + cached.modelID, + ) + + await withTimeout( + ctx.client.session.summarize({ + path: { id: sessionID }, + body: { providerID: targetProviderID, modelID: targetModelID, auto: true }, + query: { directory: ctx.directory }, + }), + PREEMPTIVE_COMPACTION_TIMEOUT_MS, + `Compaction summarize timed out after ${PREEMPTIVE_COMPACTION_TIMEOUT_MS}ms`, + ) + + compactedSessions.add(sessionID) + } catch (error) { + log("[preemptive-compaction] Compaction failed", { + sessionID, + providerID: cached.providerID, + modelID: cached.modelID, + error: String(error), + }) + ctx.client.tui.showToast({ + body: { + title: "Preemptive compaction failed", + message: `Context window is above ${Math.round(PREEMPTIVE_COMPACTION_THRESHOLD * 100)}% and auto-compaction could not run. The session may grow large. Error: ${String(error)}`, + variant: "warning", + duration: 10000, + }, + }).catch((toastError: unknown) => { + log("[preemptive-compaction] Failed to show toast", { + sessionID, + toastError: String(toastError), + }) + }) + } finally { + compactionInProgress.delete(sessionID) + } +} diff --git a/src/hooks/preemptive-compaction-types.ts b/src/hooks/preemptive-compaction-types.ts new file mode 100644 index 000000000..77efed575 --- /dev/null +++ b/src/hooks/preemptive-compaction-types.ts @@ -0,0 +1,41 @@ +export interface TokenInfo { + input: number + output: number + reasoning: number + cache: { read: number; write: number } +} + +export interface CachedCompactionState { + providerID: string + modelID: string + tokens: TokenInfo +} + +export interface PreemptiveCompactionClient { + session: { + messages: (input: { + path: { id: string } + query?: { directory: string } + }) => Promise + summarize: (input: { + path: { id: string } + body: { providerID: string; modelID: string; auto?: boolean } + query: { directory: string } + }) => Promise + } + tui: { + showToast: (input: { + body: { + title: string + message: string + variant: "warning" + duration: number + } + }) => Promise + } +} + +export interface PreemptiveCompactionContext { + client: PreemptiveCompactionClient + directory: string +} diff --git a/src/hooks/preemptive-compaction.ts b/src/hooks/preemptive-compaction.ts index ecab70676..7b4828dcb 100644 --- a/src/hooks/preemptive-compaction.ts +++ b/src/hooks/preemptive-compaction.ts @@ -1,69 +1,16 @@ -import { log } from "../shared/logger" import type { OhMyOpenCodeConfig } from "../config" -import { - resolveActualContextLimit, - type ContextLimitModelCacheState, -} from "../shared/context-limit-resolver" +import type { ContextLimitModelCacheState } from "../shared/context-limit-resolver" -import { resolveCompactionModel } from "./shared/compaction-model-resolver" import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-degradation-monitor" - -const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 60_000 -const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78 -const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000 - -declare function setTimeout(handler: () => void, timeout?: number): unknown -declare function clearTimeout(timeoutID: unknown): void - -interface TokenInfo { - input: number - output: number - reasoning: number - cache: { read: number; write: number } -} - -interface CachedCompactionState { - providerID: string - modelID: string - tokens: TokenInfo -} - -async function withTimeout( - promise: Promise, - timeoutMs: number, - errorMessage: string, -): Promise { - let timeoutID: unknown - - const timeoutPromise = new Promise((_, reject) => { - timeoutID = setTimeout(() => { - reject(new Error(errorMessage)) - }, timeoutMs) - }) - - return await Promise.race([promise, timeoutPromise]).finally(() => { - clearTimeout(timeoutID) - }) -} - -type PluginInput = { - client: { - session: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - messages: (...args: any[]) => any - // eslint-disable-next-line @typescript-eslint/no-explicit-any - summarize: (...args: any[]) => any - } - tui: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - showToast: (...args: any[]) => any - } - } - directory: string -} +import { runPreemptiveCompactionIfNeeded } from "./preemptive-compaction-trigger" +import type { + CachedCompactionState, + PreemptiveCompactionContext, + TokenInfo, +} from "./preemptive-compaction-types" export function createPreemptiveCompactionHook( - ctx: PluginInput, + ctx: PreemptiveCompactionContext, pluginConfig: OhMyOpenCodeConfig, modelCacheState?: ContextLimitModelCacheState, ) { @@ -84,78 +31,16 @@ export function createPreemptiveCompactionHook( input: { tool: string; sessionID: string; callID: string }, _output: { title: string; output: string; metadata: unknown } ) => { - const { sessionID } = input - if (compactedSessions.has(sessionID) || compactionInProgress.has(sessionID)) return - - const lastTime = lastCompactionTime.get(sessionID) - if (lastTime && Date.now() - lastTime < PREEMPTIVE_COMPACTION_COOLDOWN_MS) return - - const cached = tokenCache.get(sessionID) - if (!cached) return - - const actualLimit = resolveActualContextLimit( - cached.providerID, - cached.modelID, + await runPreemptiveCompactionIfNeeded({ + ctx, + pluginConfig, modelCacheState, - ) - - if (actualLimit === null) { - log("[preemptive-compaction] Skipping preemptive compaction: unknown context limit for model", { - providerID: cached.providerID, - modelID: cached.modelID, - }) - return - } - - const totalInputTokens = (cached.tokens.input ?? 0) + (cached.tokens.cache?.read ?? 0) - const usageRatio = totalInputTokens / actualLimit - if (usageRatio < PREEMPTIVE_COMPACTION_THRESHOLD || !cached.modelID) return - - compactionInProgress.add(sessionID) - lastCompactionTime.set(sessionID, Date.now()) - - try { - const { providerID: targetProviderID, modelID: targetModelID } = resolveCompactionModel( - pluginConfig, - sessionID, - cached.providerID, - cached.modelID, - ) - - await withTimeout( - ctx.client.session.summarize({ - path: { id: sessionID }, - body: { providerID: targetProviderID, modelID: targetModelID, auto: true } as never, - query: { directory: ctx.directory }, - }), - PREEMPTIVE_COMPACTION_TIMEOUT_MS, - `Compaction summarize timed out after ${PREEMPTIVE_COMPACTION_TIMEOUT_MS}ms`, - ) - - compactedSessions.add(sessionID) - } catch (error) { - log("[preemptive-compaction] Compaction failed", { - sessionID, - providerID: cached.providerID, - modelID: cached.modelID, - error: String(error), - }) - ctx.client.tui.showToast({ - body: { - title: "Preemptive compaction failed", - message: `Context window is above ${Math.round(PREEMPTIVE_COMPACTION_THRESHOLD * 100)}% and auto-compaction could not run. The session may grow large. Error: ${String(error)}`, - variant: "warning", - duration: 10000, - }, - }).catch((toastError: unknown) => { - log("[preemptive-compaction] Failed to show toast", { - sessionID, - toastError: String(toastError), - }) - }) - } finally { - compactionInProgress.delete(sessionID) - } + sessionID: input.sessionID, + tokenCache, + compactionInProgress, + compactedSessions, + lastCompactionTime, + }) } const eventHandler = async ({ event }: { event: { type: string; properties?: unknown } }) => { diff --git a/src/hooks/ralph-loop/oracle-verification-detector.ts b/src/hooks/ralph-loop/oracle-verification-detector.ts index 9d360282d..277ef1fe2 100644 --- a/src/hooks/ralph-loop/oracle-verification-detector.ts +++ b/src/hooks/ralph-loop/oracle-verification-detector.ts @@ -1,3 +1,4 @@ +import { extractTaskLink } from "../../features/tool-metadata-store" import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names" import { ULTRAWORK_VERIFICATION_PROMISE } from "./constants" @@ -9,8 +10,6 @@ export interface OracleVerificationEvidence { const AGENT_LINE_PATTERN = /^Agent:[ \t]*(\S+)$/im const PROMISE_TAG_PATTERN = /[ \t]*(\S+?)[ \t]*<\/promise>/is -const TASK_METADATA_PATTERN = /[ \t]*([\s\S]*?)[ \t]*<\/task_metadata>/is -const SESSION_ID_LINE_PATTERN = /^session_id:[ \t]*(\S+)$/im export function parseOracleVerificationEvidence(text: string): OracleVerificationEvidence | undefined { const trimmedText = text.trim() @@ -36,17 +35,9 @@ export function parseOracleVerificationEvidence(text: string): OracleVerificatio return undefined } - const metadataMatch = trimmedText.match(TASK_METADATA_PATTERN) - let sessionID: string | undefined - if (metadataMatch) { - const metadataContent = metadataMatch[1] - const sessionIDMatch = metadataContent.match(SESSION_ID_LINE_PATTERN) - if (sessionIDMatch) { - sessionID = sessionIDMatch[1]?.trim() - } - } + const sessionID = extractTaskLink(undefined, trimmedText).sessionId - return { agent, promise, sessionID } + return { agent, promise, sessionID } } export function isOracleVerified(text: string): boolean { diff --git a/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts b/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts index 5fcd35a2e..8f31f8ec2 100644 --- a/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts +++ b/src/hooks/ralph-loop/reset-strategy-race-condition.test.ts @@ -21,9 +21,9 @@ function createDeferred(): { } } -async function waitUntil(condition: () => boolean): Promise { +async function waitUntil(shouldTrigger: () => boolean): Promise { for (let index = 0; index < 100; index++) { - if (condition()) { + if (shouldTrigger()) { return } diff --git a/src/hooks/rules-injector/cache.test.ts b/src/hooks/rules-injector/cache.test.ts new file mode 100644 index 000000000..39a5bb472 --- /dev/null +++ b/src/hooks/rules-injector/cache.test.ts @@ -0,0 +1,74 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { randomUUID } from "node:crypto"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { createSessionCacheStore } from "./cache"; +import { RULES_INJECTOR_STORAGE } from "./constants"; +import { clearInjectedRules, saveInjectedRules } from "./storage"; + +const trackedSessionIDs: string[] = []; + +function createSessionID(prefix: string): string { + const sessionID = `${prefix}-${randomUUID()}`; + trackedSessionIDs.push(sessionID); + return sessionID; +} + +function getStoragePath(sessionID: string): string { + return join(RULES_INJECTOR_STORAGE, `${sessionID}.json`); +} + +afterEach(() => { + for (const sessionID of trackedSessionIDs.splice(0)) { + clearInjectedRules(sessionID); + } +}); + +describe("createSessionCacheStore", () => { + it("keeps factory instances isolated for the same session", () => { + // given + const sessionID = createSessionID("cache-isolation"); + const firstStore = createSessionCacheStore(); + const secondStore = createSessionCacheStore(); + const firstCache = firstStore.getSessionCache(sessionID); + + // when + firstCache.contentHashes.add("hash:first"); + firstCache.realPaths.add("/tmp/first-rule.md"); + const secondCache = secondStore.getSessionCache(sessionID); + + // then + expect([...secondCache.contentHashes]).toEqual([]); + expect([...secondCache.realPaths]).toEqual([]); + }); + + it("clears only the targeted session cache and persisted state", () => { + // given + const deletedSessionID = createSessionID("deleted-session"); + const retainedSessionID = createSessionID("retained-session"); + + saveInjectedRules(deletedSessionID, { + contentHashes: new Set(["hash:deleted"]), + realPaths: new Set(["/tmp/deleted-rule.md"]), + }); + saveInjectedRules(retainedSessionID, { + contentHashes: new Set(["hash:retained"]), + realPaths: new Set(["/tmp/retained-rule.md"]), + }); + + const store = createSessionCacheStore(); + store.getSessionCache(deletedSessionID); + const retainedCache = store.getSessionCache(retainedSessionID); + + // when + store.clearSessionCache(deletedSessionID); + const reloadedRetainedCache = store.getSessionCache(retainedSessionID); + + // then + expect(existsSync(getStoragePath(deletedSessionID))).toBe(false); + expect(existsSync(getStoragePath(retainedSessionID))).toBe(true); + expect(reloadedRetainedCache).toBe(retainedCache); + expect([...reloadedRetainedCache.contentHashes]).toEqual(["hash:retained"]); + expect([...reloadedRetainedCache.realPaths]).toEqual(["/tmp/retained-rule.md"]); + }); +}); diff --git a/src/hooks/rules-injector/cache.ts b/src/hooks/rules-injector/cache.ts index b23273144..43d64565c 100644 --- a/src/hooks/rules-injector/cache.ts +++ b/src/hooks/rules-injector/cache.ts @@ -1,4 +1,6 @@ import { clearInjectedRules, loadInjectedRules } from "./storage"; +import { createRuleScanCache } from "./rule-scan-cache"; +import type { RuleScanCache } from "./rule-scan-cache"; export type SessionInjectedRulesCache = { contentHashes: Set; @@ -25,3 +27,29 @@ export function createSessionCacheStore(): { return { getSessionCache, clearSessionCache }; } + +export function createSessionRuleScanCacheStore(): { + getSessionRuleScanCache: (sessionID: string) => RuleScanCache; + clearSessionRuleScanCache: (sessionID: string) => void; +} { + const sessionCaches = new Map(); + + function getSessionRuleScanCache(sessionID: string): RuleScanCache { + const existingCache = sessionCaches.get(sessionID); + if (existingCache) { + return existingCache; + } + + const cache = createRuleScanCache(); + sessionCaches.set(sessionID, cache); + return cache; + } + + function clearSessionRuleScanCache(sessionID: string): void { + const cache = sessionCaches.get(sessionID); + cache?.clear(); + sessionCaches.delete(sessionID); + } + + return { getSessionRuleScanCache, clearSessionRuleScanCache }; +} diff --git a/src/hooks/rules-injector/hook.ts b/src/hooks/rules-injector/hook.ts index f46af4570..b3a09ca12 100644 --- a/src/hooks/rules-injector/hook.ts +++ b/src/hooks/rules-injector/hook.ts @@ -1,8 +1,9 @@ import type { PluginInput } from "@opencode-ai/plugin"; import { createDynamicTruncator } from "../../shared/dynamic-truncator"; import { getRuleInjectionFilePath } from "./output-path"; -import { createSessionCacheStore } from "./cache"; +import { createSessionCacheStore, createSessionRuleScanCacheStore } from "./cache"; import { createRuleInjectionProcessor } from "./injector"; +import { clearProjectRootCache } from "./project-root-finder"; interface ToolExecuteInput { tool: string; @@ -36,15 +37,23 @@ export function createRulesInjectorHook( ) { const truncator = createDynamicTruncator(ctx, modelCacheState); const { getSessionCache, clearSessionCache } = createSessionCacheStore(); + const { getSessionRuleScanCache, clearSessionRuleScanCache } = + createSessionRuleScanCacheStore(); const { processFilePathForInjection } = createRuleInjectionProcessor({ workspaceDirectory: ctx.directory, truncator, getSessionCache, + getSessionRuleScanCache, ruleFinderOptions: options?.skipClaudeUserRules ? { skipClaudeUserRules: true } : undefined, }); + function clearSessionState(sessionID: string): void { + clearSessionCache(sessionID); + clearSessionRuleScanCache(sessionID); + } + const toolExecuteAfter = async ( input: ToolExecuteInput, output: ToolExecuteOutput @@ -73,16 +82,18 @@ export function createRulesInjectorHook( if (event.type === "session.deleted") { const sessionInfo = props?.info as { id?: string } | undefined; if (sessionInfo?.id) { - clearSessionCache(sessionInfo.id); + clearSessionState(sessionInfo.id); } + clearProjectRootCache(); } if (event.type === "session.compacted") { const sessionID = (props?.sessionID ?? (props?.info as { id?: string } | undefined)?.id) as string | undefined; if (sessionID) { - clearSessionCache(sessionID); + clearSessionState(sessionID); } + clearProjectRootCache(); } }; diff --git a/src/hooks/rules-injector/injector.ts b/src/hooks/rules-injector/injector.ts index dc4e9fe29..0cd64be5b 100644 --- a/src/hooks/rules-injector/injector.ts +++ b/src/hooks/rules-injector/injector.ts @@ -12,6 +12,7 @@ import { import { parseRuleFrontmatter } from "./parser"; import { saveInjectedRules } from "./storage"; import type { SessionInjectedRulesCache } from "./cache"; +import type { RuleScanCache } from "./rule-scan-cache"; import type { RuleMetadata } from "./types"; type ToolExecuteOutput = { @@ -56,6 +57,7 @@ export function createRuleInjectionProcessor(deps: { workspaceDirectory: string; truncator: DynamicTruncator; getSessionCache: (sessionID: string) => SessionInjectedRulesCache; + getSessionRuleScanCache?: (sessionID: string) => RuleScanCache; ruleFinderOptions?: FindRuleFilesOptions; readFileSync?: typeof readFileSync; statSync?: typeof statSync; @@ -76,6 +78,7 @@ export function createRuleInjectionProcessor(deps: { workspaceDirectory, truncator, getSessionCache, + getSessionRuleScanCache, ruleFinderOptions, readFileSync: readRuleFileSync = readFileSync, statSync: statRuleSync = statSync, @@ -121,9 +124,16 @@ export function createRuleInjectionProcessor(deps: { const projectRoot = findProjectRoot(resolved); const cache = getSessionCache(sessionID); + const ruleScanCache = getSessionRuleScanCache?.(sessionID); const home = getHomeDir(); - const ruleFileCandidates = findRuleFiles(projectRoot, home, resolved, ruleFinderOptions); + const ruleFileCandidates = findRuleFiles( + projectRoot, + home, + resolved, + ruleFinderOptions, + ruleScanCache, + ); const toInject: RuleToInject[] = []; let dirty = false; diff --git a/src/hooks/rules-injector/project-root-finder.test.ts b/src/hooks/rules-injector/project-root-finder.test.ts new file mode 100644 index 000000000..35d442290 --- /dev/null +++ b/src/hooks/rules-injector/project-root-finder.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it, mock } from "bun:test"; + +describe("findProjectRoot", () => { + afterEach(async () => { + const actualFileSystem = await import("node:fs"); + mock.module("node:fs", () => actualFileSystem); + }); + + it("memoizes repeated lookups for the same start path and resets on cache clear", async () => { + // given + const actualFileSystem = await import("node:fs"); + const projectRoot = "/workspace/project"; + const startPath = `${projectRoot}/src/file.ts`; + const packageJsonPath = `${projectRoot}/package.json`; + + const existsSyncSpy = mock((path: string) => path === packageJsonPath); + const statSyncSpy = mock(() => ({ isDirectory: () => false })); + + mock.module("node:fs", () => ({ + ...actualFileSystem, + existsSync: existsSyncSpy, + statSync: statSyncSpy, + })); + + const { clearProjectRootCache, findProjectRoot } = await import( + `./project-root-finder.ts?memoization=${Date.now()}` + ); + + // when + const firstResult = findProjectRoot(startPath); + const firstExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + const secondResult = findProjectRoot(startPath); + const secondExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + clearProjectRootCache(); + const thirdResult = findProjectRoot(startPath); + + // then + expect(firstResult).toBe(projectRoot); + expect(secondResult).toBe(projectRoot); + expect(thirdResult).toBe(projectRoot); + expect(firstExistsSyncCallCount).toBeGreaterThan(0); + expect(secondExistsSyncCallCount).toBe(firstExistsSyncCallCount); + expect(existsSyncSpy).toHaveBeenCalledTimes(firstExistsSyncCallCount * 2); + }); +}); diff --git a/src/hooks/rules-injector/project-root-finder.ts b/src/hooks/rules-injector/project-root-finder.ts index da697f0d9..ea552e0c9 100644 --- a/src/hooks/rules-injector/project-root-finder.ts +++ b/src/hooks/rules-injector/project-root-finder.ts @@ -2,6 +2,12 @@ import { existsSync, statSync } from "node:fs"; import { dirname, join } from "node:path"; import { PROJECT_MARKERS } from "./constants"; +const projectRootCache = new Map(); + +export function clearProjectRootCache(): void { + projectRootCache.clear(); +} + /** * Find project root by walking up from startPath. * Checks for PROJECT_MARKERS (.git, pyproject.toml, package.json, etc.) @@ -10,6 +16,16 @@ import { PROJECT_MARKERS } from "./constants"; * @returns Project root path or null if not found */ export function findProjectRoot(startPath: string): string | null { + if (projectRootCache.has(startPath)) { + return projectRootCache.get(startPath) ?? null; + } + + const projectRoot = findProjectRootWithoutCache(startPath); + projectRootCache.set(startPath, projectRoot); + return projectRoot; +} + +function findProjectRootWithoutCache(startPath: string): string | null { let current: string; try { diff --git a/src/hooks/rules-injector/rule-file-finder.ts b/src/hooks/rules-injector/rule-file-finder.ts index 98bd6942b..7059804d4 100644 --- a/src/hooks/rules-injector/rule-file-finder.ts +++ b/src/hooks/rules-injector/rule-file-finder.ts @@ -1,51 +1,108 @@ import { existsSync, statSync } from "node:fs"; -import { dirname, join } from "node:path"; +import { dirname, join, sep } from "node:path"; import { + OPENCODE_USER_RULE_DIRS, PROJECT_RULE_FILES, PROJECT_RULE_SUBDIRS, USER_RULE_DIR, - OPENCODE_USER_RULE_DIRS, } from "./constants"; -import type { RuleFileCandidate } from "./types"; +import type { RuleScanCache } from "./rule-scan-cache"; import { findRuleFilesRecursive, safeRealpathSync } from "./rule-file-scanner"; +import type { RuleFileCandidate } from "./types"; export interface FindRuleFilesOptions { - /** - * When true, skip loading rules from ~/.claude/rules/. - * Use when claude_code integration is disabled to prevent - * Claude Code-specific instructions from leaking into non-Claude agents. - */ skipClaudeUserRules?: boolean; } -/** - * Find all rule files for a given context. - * Searches from currentFile upward to projectRoot for rule directories, - * then user-level directory (~/.claude/rules). - * - * IMPORTANT: This searches EVERY directory from file to project root. - * Not just the project root itself. - * - * @param projectRoot - Project root path (or null if outside any project) - * @param homeDir - User home directory - * @param currentFile - Current file being edited (for distance calculation) - * @returns Array of rule file candidates sorted by distance - */ +function getUserRuleDirs(homeDir: string, skipClaudeUserRules: boolean): string[] { + const userRuleDirs = OPENCODE_USER_RULE_DIRS.map((dir) => join(homeDir, dir)); + if (!skipClaudeUserRules) { + userRuleDirs.push(join(homeDir, USER_RULE_DIR)); + } + return userRuleDirs; +} + +function createCacheKey( + projectRoot: string | null, + startDir: string, + skipClaudeUserRules: boolean, +): string { + return `${projectRoot ?? ""}|${startDir}|${skipClaudeUserRules ? "1" : "0"}`; +} + +function createCachedCandidate( + filePath: string, + projectRoot: string | null, + startDir: string, + userRuleDirs: string[], +): RuleFileCandidate | undefined { + const realPath = safeRealpathSync(filePath); + + for (const userRuleDir of userRuleDirs) { + if (filePath.startsWith(`${userRuleDir}${sep}`)) { + return { path: filePath, realPath, isGlobal: true, distance: 9999 }; + } + } + + if (projectRoot) { + for (const ruleFile of PROJECT_RULE_FILES) { + if (filePath === join(projectRoot, ruleFile)) { + return { + path: filePath, + realPath, + isGlobal: false, + distance: 0, + isSingleFile: true, + }; + } + } + } + + let currentDir = startDir; + let distance = 0; + while (true) { + for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) { + const ruleDir = join(currentDir, parent, subdir); + if (filePath.startsWith(`${ruleDir}${sep}`)) { + return { path: filePath, realPath, isGlobal: false, distance }; + } + } + + if (projectRoot && currentDir === projectRoot) break; + const parentDir = dirname(currentDir); + if (parentDir === currentDir) break; + currentDir = parentDir; + distance += 1; + } + + return undefined; +} + export function findRuleFiles( projectRoot: string | null, homeDir: string, currentFile: string, options?: FindRuleFilesOptions, + cache?: RuleScanCache, ): RuleFileCandidate[] { + const startDir = dirname(currentFile); + const skipClaudeUserRules = options?.skipClaudeUserRules ?? false; + const userRuleDirs = getUserRuleDirs(homeDir, skipClaudeUserRules); + const cacheKey = createCacheKey(projectRoot, startDir, skipClaudeUserRules); + const cachedPaths = cache?.get(cacheKey); + + if (cachedPaths) { + return cachedPaths + .map((filePath) => createCachedCandidate(filePath, projectRoot, startDir, userRuleDirs)) + .filter((candidate): candidate is RuleFileCandidate => candidate !== undefined); + } + const candidates: RuleFileCandidate[] = []; const seenRealPaths = new Set(); - - // Search from current file's directory up to project root - let currentDir = dirname(currentFile); + let currentDir = startDir; let distance = 0; while (true) { - // Search rule directories in current directory for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) { const ruleDir = join(currentDir, parent, subdir); const files: string[] = []; @@ -55,60 +112,41 @@ export function findRuleFiles( const realPath = safeRealpathSync(filePath); if (seenRealPaths.has(realPath)) continue; seenRealPaths.add(realPath); - - candidates.push({ - path: filePath, - realPath, - isGlobal: false, - distance, - }); + candidates.push({ path: filePath, realPath, isGlobal: false, distance }); } } - // Stop at project root or filesystem root if (projectRoot && currentDir === projectRoot) break; const parentDir = dirname(currentDir); if (parentDir === currentDir) break; currentDir = parentDir; - distance++; + distance += 1; } - // Check for single-file rules at project root (e.g., .github/copilot-instructions.md) if (projectRoot) { for (const ruleFile of PROJECT_RULE_FILES) { const filePath = join(projectRoot, ruleFile); - if (existsSync(filePath)) { - try { - const stat = statSync(filePath); - if (stat.isFile()) { - const realPath = safeRealpathSync(filePath); - if (!seenRealPaths.has(realPath)) { - seenRealPaths.add(realPath); - candidates.push({ - path: filePath, - realPath, - isGlobal: false, - distance: 0, - isSingleFile: true, - }); - } - } - } catch { - // Skip if file can't be read - } + if (!existsSync(filePath)) continue; + + try { + const stat = statSync(filePath); + if (!stat.isFile()) continue; + const realPath = safeRealpathSync(filePath); + if (seenRealPaths.has(realPath)) continue; + seenRealPaths.add(realPath); + candidates.push({ + path: filePath, + realPath, + isGlobal: false, + distance: 0, + isSingleFile: true, + }); + } catch { + continue; } } } - // Search user-level rule directories - // Always search OpenCode-native dirs (~/.sisyphus/rules, ~/.opencode/rules) - const userRuleDirs: string[] = OPENCODE_USER_RULE_DIRS.map((dir) => join(homeDir, dir)); - - // Only search ~/.claude/rules when claude_code integration is not disabled - if (!options?.skipClaudeUserRules) { - userRuleDirs.push(join(homeDir, USER_RULE_DIR)); - } - for (const userRuleDir of userRuleDirs) { const userFiles: string[] = []; findRuleFilesRecursive(userRuleDir, userFiles); @@ -117,23 +155,21 @@ export function findRuleFiles( const realPath = safeRealpathSync(filePath); if (seenRealPaths.has(realPath)) continue; seenRealPaths.add(realPath); - - candidates.push({ - path: filePath, - realPath, - isGlobal: true, - distance: 9999, // Global rules always have max distance - }); + candidates.push({ path: filePath, realPath, isGlobal: true, distance: 9999 }); } } - // Sort by distance (closest first, then global rules last) - candidates.sort((a, b) => { - if (a.isGlobal !== b.isGlobal) { - return a.isGlobal ? 1 : -1; + candidates.sort((left, right) => { + if (left.isGlobal !== right.isGlobal) { + return left.isGlobal ? 1 : -1; } - return a.distance - b.distance; + return left.distance - right.distance; }); + cache?.set( + cacheKey, + candidates.map((candidate) => candidate.path), + ); + return candidates; } diff --git a/src/hooks/rules-injector/rule-file-scanner.test.ts b/src/hooks/rules-injector/rule-file-scanner.test.ts new file mode 100644 index 000000000..cadf4c3f1 --- /dev/null +++ b/src/hooks/rules-injector/rule-file-scanner.test.ts @@ -0,0 +1,42 @@ +import { afterEach, describe, expect, test } from "bun:test"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { randomUUID } from "node:crypto"; +import { findRuleFilesRecursive } from "./rule-file-scanner"; + +const createdDirectories: string[] = []; + +afterEach(() => { + for (const directory of createdDirectories.splice(0)) { + if (existsSync(directory)) { + rmSync(directory, { recursive: true, force: true }); + } + } +}); + +describe("findRuleFilesRecursive", () => { + test("returns rule files outside excluded nested directories", () => { + // given + const temporaryDirectory = join(tmpdir(), `perf-d01-${randomUUID()}`); + createdDirectories.push(temporaryDirectory); + + const rulesDirectory = join(temporaryDirectory, ".sisyphus", "rules"); + mkdirSync(join(rulesDirectory, "node_modules", "fake"), { recursive: true }); + mkdirSync(join(rulesDirectory, ".git"), { recursive: true }); + writeFileSync(join(rulesDirectory, "foo.md"), "root rule"); + writeFileSync( + join(rulesDirectory, "node_modules", "fake", "x.md"), + "ignored node_modules rule", + ); + writeFileSync(join(rulesDirectory, ".git", "x.md"), "ignored git rule"); + + const results: string[] = []; + + // when + findRuleFilesRecursive(rulesDirectory, results); + + // then + expect(results).toEqual([join(rulesDirectory, "foo.md")]); + }); +}); diff --git a/src/hooks/rules-injector/rule-file-scanner.ts b/src/hooks/rules-injector/rule-file-scanner.ts index ffd87d8a9..2cd853d07 100644 --- a/src/hooks/rules-injector/rule-file-scanner.ts +++ b/src/hooks/rules-injector/rule-file-scanner.ts @@ -1,5 +1,6 @@ import { existsSync, readdirSync, realpathSync } from "node:fs"; import { join } from "node:path"; +import { EXCLUDED_DIRS } from "../../shared"; import { GITHUB_INSTRUCTIONS_PATTERN, RULE_EXTENSIONS } from "./constants"; function isGitHubInstructionsDir(dir: string): boolean { @@ -28,6 +29,7 @@ export function findRuleFilesRecursive(dir: string, results: string[]): void { const fullPath = join(dir, entry.name); if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue; findRuleFilesRecursive(fullPath, results); } else if (entry.isFile()) { if (isValidRuleFile(entry.name, dir)) { diff --git a/src/hooks/rules-injector/rule-scan-cache.test.ts b/src/hooks/rules-injector/rule-scan-cache.test.ts new file mode 100644 index 000000000..778cf341a --- /dev/null +++ b/src/hooks/rules-injector/rule-scan-cache.test.ts @@ -0,0 +1,91 @@ +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +function createImportSuffix(): string { + return `?test=${Date.now()}-${Math.random()}`; +} + +describe("createRuleScanCache", () => { + afterEach(() => { + mock.restore(); + }); + + it("returns undefined before set, returns stored value, and clears entries", async () => { + // given + const { createRuleScanCache } = await import(`./rule-scan-cache${createImportSuffix()}`); + const cache = createRuleScanCache(); + const value = ["a", "b"]; + + // when + const initialValue = cache.get("k1"); + cache.set("k1", value); + const storedValue = cache.get("k1"); + cache.clear(); + const clearedValue = cache.get("k1"); + + // then + expect(initialValue).toBeUndefined(); + expect(storedValue).toEqual(value); + expect(clearedValue).toBeUndefined(); + }); +}); + +describe("findRuleFiles with scan cache", () => { + let testRoot = ""; + let homeDir = ""; + let projectRoot = ""; + let currentFile = ""; + let expectedRuleFile = ""; + let expectedRuleDir = ""; + + beforeEach(() => { + testRoot = join(tmpdir(), `rule-scan-cache-test-${Date.now()}`); + homeDir = join(testRoot, "home"); + projectRoot = join(testRoot, "project"); + currentFile = join(projectRoot, "src", "index.ts"); + expectedRuleDir = join(projectRoot, ".github", "instructions"); + expectedRuleFile = join(expectedRuleDir, "typescript.instructions.md"); + + mkdirSync(join(projectRoot, ".git"), { recursive: true }); + mkdirSync(join(projectRoot, "src"), { recursive: true }); + mkdirSync(homeDir, { recursive: true }); + writeFileSync(currentFile, "export const value = 1;\n"); + }); + + afterEach(() => { + mock.restore(); + if (existsSync(testRoot)) { + rmSync(testRoot, { recursive: true, force: true }); + } + }); + + it("reuses cached directory scan results for identical inputs", async () => { + // given + const findRuleFilesRecursive = mock((directoryPath: string, results: string[]) => { + if (directoryPath === expectedRuleDir) { + results.push(expectedRuleFile); + } + }); + + mock.module("./rule-file-scanner", () => ({ + findRuleFilesRecursive, + safeRealpathSync: (filePath: string) => filePath, + })); + + const { createRuleScanCache } = await import(`./rule-scan-cache${createImportSuffix()}`); + const { findRuleFiles } = await import(`./rule-file-finder${createImportSuffix()}`); + const cache = createRuleScanCache(); + + // when + const firstCandidates = findRuleFiles(projectRoot, homeDir, currentFile, undefined, cache); + const firstInvocationCount = findRuleFilesRecursive.mock.calls.length; + const secondCandidates = findRuleFiles(projectRoot, homeDir, currentFile, undefined, cache); + + // then + expect(firstCandidates).toEqual(secondCandidates); + expect(firstInvocationCount).toBeGreaterThan(0); + expect(findRuleFilesRecursive).toHaveBeenCalledTimes(firstInvocationCount); + }); +}); diff --git a/src/hooks/rules-injector/rule-scan-cache.ts b/src/hooks/rules-injector/rule-scan-cache.ts new file mode 100644 index 000000000..fc8ff1a20 --- /dev/null +++ b/src/hooks/rules-injector/rule-scan-cache.ts @@ -0,0 +1,21 @@ +export type RuleScanCache = { + get: (key: string) => string[] | undefined; + set: (key: string, value: string[]) => void; + clear: () => void; +}; + +export function createRuleScanCache(): RuleScanCache { + const cache = new Map(); + + return { + get(key: string): string[] | undefined { + return cache.get(key); + }, + set(key: string, value: string[]): void { + cache.set(key, value); + }, + clear(): void { + cache.clear(); + }, + }; +} diff --git a/src/hooks/rules-injector/storage.test.ts b/src/hooks/rules-injector/storage.test.ts new file mode 100644 index 000000000..e12c4a45e --- /dev/null +++ b/src/hooks/rules-injector/storage.test.ts @@ -0,0 +1,57 @@ +import { afterEach, describe, expect, it } from "bun:test"; +import { randomUUID } from "node:crypto"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { RULES_INJECTOR_STORAGE } from "./constants"; +import { + clearInjectedRules, + loadInjectedRules, + saveInjectedRules, +} from "./storage"; + +const trackedSessionIDs: string[] = []; + +function createSessionID(prefix: string): string { + const sessionID = `${prefix}-${randomUUID()}`; + trackedSessionIDs.push(sessionID); + return sessionID; +} + +function getStoragePath(sessionID: string): string { + return join(RULES_INJECTOR_STORAGE, `${sessionID}.json`); +} + +afterEach(() => { + for (const sessionID of trackedSessionIDs.splice(0)) { + clearInjectedRules(sessionID); + } +}); + +describe("storage", () => { + it("reads back only the requested session data from session-scoped files", () => { + // given + const firstSessionID = createSessionID("storage-first"); + const secondSessionID = createSessionID("storage-second"); + + saveInjectedRules(firstSessionID, { + contentHashes: new Set(["hash:first"]), + realPaths: new Set(["/tmp/first-rule.md"]), + }); + saveInjectedRules(secondSessionID, { + contentHashes: new Set(["hash:second"]), + realPaths: new Set(["/tmp/second-rule.md"]), + }); + + // when + const firstLoaded = loadInjectedRules(firstSessionID); + const secondLoaded = loadInjectedRules(secondSessionID); + + // then + expect(existsSync(getStoragePath(firstSessionID))).toBe(true); + expect(existsSync(getStoragePath(secondSessionID))).toBe(true); + expect([...firstLoaded.contentHashes]).toEqual(["hash:first"]); + expect([...firstLoaded.realPaths]).toEqual(["/tmp/first-rule.md"]); + expect([...secondLoaded.contentHashes]).toEqual(["hash:second"]); + expect([...secondLoaded.realPaths]).toEqual(["/tmp/second-rule.md"]); + }); +}); diff --git a/src/hooks/runtime-fallback/dispose.test.ts b/src/hooks/runtime-fallback/dispose.test.ts index a5cb46ef7..643b7c8fb 100644 --- a/src/hooks/runtime-fallback/dispose.test.ts +++ b/src/hooks/runtime-fallback/dispose.test.ts @@ -107,9 +107,10 @@ describe("createRuntimeFallbackHook dispose", () => { globalThis.clearTimeout = originalClearTimeout }) - test("#given runtime-fallback hook created #when dispose() is called #then cleanup interval is cleared", () => { + test("#given runtime-fallback hook handles its first event #when dispose() is called #then cleanup interval is cleared", async () => { // given const hook = createRuntimeFallbackHook(createMockContext(), { pluginConfig: {} }) + await hook.event({ event: { type: "session.created", properties: {} } }) // when hook.dispose?.() @@ -125,10 +126,10 @@ describe("createRuntimeFallbackHook dispose", () => { const fallbackTimeout = setTimeout(() => {}, 60_000) capturedDeps?.sessionStates.set("session-1", { - originalModel: "anthropic/claude-opus-4-6", + originalModel: "anthropic/claude-opus-4-7", currentModel: "openai/gpt-5.4", fallbackIndex: 1, - failedModels: new Map([["anthropic/claude-opus-4-6", 1]]), + failedModels: new Map([["anthropic/claude-opus-4-7", 1]]), attemptCount: 1, }) capturedDeps?.sessionLastAccess.set("session-1", Date.now()) diff --git a/src/hooks/runtime-fallback/error-classifier.test.ts b/src/hooks/runtime-fallback/error-classifier.test.ts index 958babe5f..c9eef6e06 100644 --- a/src/hooks/runtime-fallback/error-classifier.test.ts +++ b/src/hooks/runtime-fallback/error-classifier.test.ts @@ -7,7 +7,7 @@ describe("runtime-fallback error classifier", () => { //#given const info = { status: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when @@ -21,7 +21,7 @@ describe("runtime-fallback error classifier", () => { //#given const info = { status: - "All credentials for model claude-opus-4-6 are cooldown [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooldown [retrying in 7m 56s attempt #1]", } //#when @@ -49,7 +49,7 @@ describe("runtime-fallback error classifier", () => { //#given const error = { message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when @@ -65,8 +65,8 @@ describe("runtime-fallback error classifier", () => { name: "ProviderModelNotFoundError", data: { providerID: "anthropic", - modelID: "claude-opus-4-6", - message: "Model not found: anthropic/claude-opus-4-6.", + modelID: "claude-opus-4-7", + message: "Model not found: anthropic/claude-opus-4-7.", }, } diff --git a/src/hooks/runtime-fallback/fallback-models.test.ts b/src/hooks/runtime-fallback/fallback-models.test.ts index 7cf3f8e32..ebfa8fbc9 100644 --- a/src/hooks/runtime-fallback/fallback-models.test.ts +++ b/src/hooks/runtime-fallback/fallback-models.test.ts @@ -15,7 +15,7 @@ describe("runtime-fallback fallback-models", () => { const pluginConfig = { categories: { quick: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any @@ -24,7 +24,7 @@ describe("runtime-fallback fallback-models", () => { const result = getFallbackModelsForSession(sessionID, undefined, pluginConfig) //#then - expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-6"]) + expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-7"]) }) test("uses agent-specific fallback_models when agent is resolved", () => { @@ -32,7 +32,7 @@ describe("runtime-fallback fallback-models", () => { const pluginConfig = { agents: { oracle: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any @@ -41,7 +41,7 @@ describe("runtime-fallback fallback-models", () => { const result = getFallbackModelsForSession("ses_runtime_fallback_agent", "oracle", pluginConfig) //#then - expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-6"]) + expect(result).toEqual(["openai/gpt-5.2", "anthropic/claude-opus-4-7"]) }) test("does not fall back to another agent chain when agent cannot be resolved", () => { @@ -52,7 +52,7 @@ describe("runtime-fallback fallback-models", () => { fallback_models: ["quotio/gpt-5.2", "quotio/glm-5", "quotio/kimi-k2.5"], }, oracle: { - fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-6"], + fallback_models: ["openai/gpt-5.2", "anthropic/claude-opus-4-7"], }, }, } as any diff --git a/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts b/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts index 912100011..c008649bd 100644 --- a/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts +++ b/src/hooks/runtime-fallback/hook-dispose-cleanup.test.ts @@ -51,7 +51,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -63,7 +63,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { status: { type: "retry", attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -77,7 +77,7 @@ describe("createRuntimeFallbackHook dispose retry-key cleanup", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) await hook.event(retryEvent) diff --git a/src/hooks/runtime-fallback/hook.init.test.ts b/src/hooks/runtime-fallback/hook.init.test.ts new file mode 100644 index 000000000..06a7e658c --- /dev/null +++ b/src/hooks/runtime-fallback/hook.init.test.ts @@ -0,0 +1,124 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" +import type { OhMyOpenCodeConfig } from "../../config" +import type { HookDeps, RuntimeFallbackInterval, RuntimeFallbackPluginInput } from "./types" + +type RuntimeFallbackModule = typeof import("./hook") + +const loadPluginConfigMock = mock(() => ({} satisfies OhMyOpenCodeConfig)) +const createAutoRetryHelpersMock = mock((_deps: HookDeps) => { + void _deps + + return { + abortSessionRequest: async () => {}, + clearSessionFallbackTimeout: () => {}, + scheduleSessionFallbackTimeout: () => {}, + autoRetryWithFallback: async () => {}, + resolveAgentForSessionFromContext: async () => undefined, + cleanupStaleSessions: () => {}, + } +}) +const createEventHandlerMock = mock(() => async () => {}) +const createMessageUpdateHandlerMock = mock(() => async () => {}) +const createChatMessageHandlerMock = mock(() => async () => {}) + +function registerModuleMocks(): void { + mock.module("../../plugin-config", () => ({ + loadPluginConfig: loadPluginConfigMock, + })) + + mock.module("./auto-retry", () => ({ + createAutoRetryHelpers: createAutoRetryHelpersMock, + })) + + mock.module("./event-handler", () => ({ + createEventHandler: createEventHandlerMock, + })) + + mock.module("./message-update-handler", () => ({ + createMessageUpdateHandler: createMessageUpdateHandlerMock, + })) + + mock.module("./chat-message-handler", () => ({ + createChatMessageHandler: createChatMessageHandlerMock, + })) +} + +function createMockContext(): RuntimeFallbackPluginInput { + return { + client: { + session: { + abort: async () => ({}), + messages: async () => ({}), + promptAsync: async () => ({}), + }, + tui: { + showToast: async () => ({}), + }, + }, + directory: "/test", + } +} + +function createMockInterval(): RuntimeFallbackInterval { + return { + unref: () => {}, + } +} + +describe("createRuntimeFallbackHook initialization", () => { + const originalSetInterval = globalThis.setInterval + let setIntervalCalls = 0 + let createRuntimeFallbackHook: RuntimeFallbackModule["createRuntimeFallbackHook"] + + beforeEach(async () => { + mock.restore() + registerModuleMocks() + loadPluginConfigMock.mockClear() + createAutoRetryHelpersMock.mockClear() + createEventHandlerMock.mockClear() + createMessageUpdateHandlerMock.mockClear() + createChatMessageHandlerMock.mockClear() + setIntervalCalls = 0 + + globalThis.setInterval = ((callback: Parameters[0], delay?: number) => { + void callback + void delay + setIntervalCalls += 1 + return createMockInterval() as ReturnType + }) as typeof globalThis.setInterval + + const cacheBuster = `${Date.now()}-${Math.random()}` + const runtimeFallbackModule: RuntimeFallbackModule = await import(`./hook?test=${cacheBuster}`) + createRuntimeFallbackHook = runtimeFallbackModule.createRuntimeFallbackHook + }) + + afterEach(() => { + globalThis.setInterval = originalSetInterval + mock.restore() + }) + + test("#given injected pluginConfig #when the hook factory runs #then loadPluginConfig is not called", () => { + // given + const pluginConfig = {} satisfies OhMyOpenCodeConfig + + // when + createRuntimeFallbackHook(createMockContext(), { pluginConfig }) + + // then + expect(loadPluginConfigMock).not.toHaveBeenCalled() + }) + + test("#given a fresh hook #when the first event arrives #then cleanup interval starts only once", async () => { + // given + const hook = createRuntimeFallbackHook(createMockContext(), { pluginConfig: {} }) + + // when + expect(setIntervalCalls).toBe(0) + await hook.event({ event: { type: "session.created", properties: {} } }) + expect(setIntervalCalls).toBe(1) + await hook.event({ event: { type: "session.error", properties: {} } }) + + // then + expect(setIntervalCalls).toBe(1) + }) +}) diff --git a/src/hooks/runtime-fallback/hook.ts b/src/hooks/runtime-fallback/hook.ts index 2a13d507e..f3509ab0a 100644 --- a/src/hooks/runtime-fallback/hook.ts +++ b/src/hooks/runtime-fallback/hook.ts @@ -1,7 +1,5 @@ import type { HookDeps, RuntimeFallbackHook, RuntimeFallbackInterval, RuntimeFallbackOptions, RuntimeFallbackPluginInput, RuntimeFallbackTimeout } from "./types" -import { DEFAULT_CONFIG, HOOK_NAME } from "./constants" -import { log } from "../../shared/logger" -import { loadPluginConfig } from "../../plugin-config" +import { DEFAULT_CONFIG } from "./constants" import { createAutoRetryHelpers } from "./auto-retry" import { createEventHandler } from "./event-handler" import { createMessageUpdateHandler } from "./message-update-handler" @@ -24,20 +22,11 @@ export function createRuntimeFallbackHook( notify_on_fallback: options?.config?.notify_on_fallback ?? DEFAULT_CONFIG.notify_on_fallback, } - let pluginConfig = options?.pluginConfig - if (!pluginConfig) { - try { - pluginConfig = loadPluginConfig(ctx.directory, ctx) - } catch { - log(`[${HOOK_NAME}] Plugin config not available`) - } - } - const deps: HookDeps = { ctx, config, options, - pluginConfig, + pluginConfig: options?.pluginConfig, sessionStates: new Map(), sessionLastAccess: new Map(), sessionRetryInFlight: new Set(), @@ -51,10 +40,23 @@ export function createRuntimeFallbackHook( const messageUpdateHandler = createMessageUpdateHandler(deps, helpers) const chatMessageHandler = createChatMessageHandler(deps) - const cleanupInterval = setInterval(helpers.cleanupStaleSessions, 5 * 60 * 1000) - cleanupInterval.unref() + let cleanupInterval: RuntimeFallbackInterval | null = null + let intervalStarted = false + + const ensureInterval = (): void => { + if (intervalStarted) return + + intervalStarted = true + cleanupInterval = setInterval(helpers.cleanupStaleSessions, 5 * 60 * 1000) + + if (typeof cleanupInterval.unref === "function") { + cleanupInterval.unref() + } + } const eventHandler = async ({ event }: { event: { type: string; properties?: unknown } }) => { + ensureInterval() + if (event.type === "message.updated") { if (!config.enabled) return const props = event.properties as Record | undefined @@ -65,7 +67,9 @@ export function createRuntimeFallbackHook( } const dispose = () => { - clearInterval(cleanupInterval) + if (cleanupInterval) { + clearInterval(cleanupInterval) + } for (const fallbackTimeout of deps.sessionFallbackTimeouts.values()) { clearTimeout(fallbackTimeout) diff --git a/src/hooks/runtime-fallback/index.test.ts b/src/hooks/runtime-fallback/index.test.ts index 8c9ad6aa4..76e29c2d3 100644 --- a/src/hooks/runtime-fallback/index.test.ts +++ b/src/hooks/runtime-fallback/index.test.ts @@ -329,7 +329,7 @@ describe("runtime-fallback", () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "anthropic/claude-opus-4.6", + "anthropic/claude-opus-4.7", "openai/gpt-5.4", ]), }) @@ -365,14 +365,14 @@ describe("runtime-fallback", () => { type: "session.error", properties: { sessionID, - error: { name: "UnknownError", data: { message: "Model not found: anthropic/claude-opus-4.6." } }, + error: { name: "UnknownError", data: { message: "Model not found: anthropic/claude-opus-4.7." } }, }, }, }) const fallbackLogs = logCalls.filter((c) => c.msg.includes("Preparing fallback")) expect(fallbackLogs.length).toBeGreaterThanOrEqual(2) - expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.7", to: "openai/gpt-5.4" }) const nonRetryLog = logCalls.find( (c) => c.msg.includes("Error not retryable") && (c.data as { sessionID?: string } | undefined)?.sessionID === sessionID @@ -384,7 +384,7 @@ describe("runtime-fallback", () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "anthropic/claude-opus-4.6", + "anthropic/claude-opus-4.7", "openai/gpt-5.4", ]), }) @@ -421,8 +421,8 @@ describe("runtime-fallback", () => { name: "ProviderModelNotFoundError", data: { providerID: "anthropic", - modelID: "claude-opus-4.6", - message: "Model not found: anthropic/claude-opus-4.6.", + modelID: "claude-opus-4.7", + message: "Model not found: anthropic/claude-opus-4.7.", }, }, }, @@ -431,7 +431,7 @@ describe("runtime-fallback", () => { const fallbackLogs = logCalls.filter((c) => c.msg.includes("Preparing fallback")) expect(fallbackLogs.length).toBeGreaterThanOrEqual(2) - expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLogs[1]?.data).toMatchObject({ from: "anthropic/claude-opus-4.7", to: "openai/gpt-5.4" }) }) test("should bootstrap session.error fallback from session category model and preserve variant", async () => { @@ -500,7 +500,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "github-copilot/claude-opus-4.6" } }, + properties: { info: { id: sessionID, model: "github-copilot/claude-opus-4.7" } }, }, }) @@ -511,7 +511,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", status: "Too Many Requests: quota exceeded [retrying in ~2 weeks attempt #1]", }, @@ -524,13 +524,13 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "github-copilot/claude-opus-4.6", to: "openai/gpt-5.4" }) + expect(fallbackLog?.data).toMatchObject({ from: "github-copilot/claude-opus-4.7", to: "openai/gpt-5.4" }) }) test("should trigger fallback on OpenAI auto-retry signal in message.updated", async () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), }) const sessionID = "test-session-openai-auto-retry" @@ -562,7 +562,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-6" }) + expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-7" }) }) test("should trigger fallback on auto-retry signal in assistant text parts", async () => { @@ -577,7 +577,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -588,7 +588,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", }, parts: [ { @@ -605,7 +605,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) }) test("should trigger fallback when auto-retry text parts are nested under info.parts", async () => { @@ -620,7 +620,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -631,7 +631,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", parts: [ { type: "text", @@ -648,7 +648,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) }) test("should trigger fallback on session.status auto-retry signal", async () => { @@ -682,7 +682,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -695,7 +695,7 @@ describe("runtime-fallback", () => { type: "retry", next: 476, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -706,7 +706,7 @@ describe("runtime-fallback", () => { const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback")) expect(fallbackLog).toBeDefined() - expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" }) + expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-7", to: "openai/gpt-5.2" }) expect(promptCalls.length).toBe(1) }) @@ -741,7 +741,7 @@ describe("runtime-fallback", () => { await hook.event({ event: { type: "session.created", - properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } }, + properties: { info: { id: sessionID, model: "quotio/claude-opus-4-7" } }, }, }) @@ -754,7 +754,7 @@ describe("runtime-fallback", () => { type: "retry", next: 476, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", }, }, }, @@ -769,7 +769,7 @@ describe("runtime-fallback", () => { type: "retry", next: 475, attempt: 1, - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 55s attempt #1]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 55s attempt #1]", }, }, }, @@ -781,7 +781,7 @@ describe("runtime-fallback", () => { test("should NOT trigger fallback on auto-retry signal when timeout_seconds is 0", async () => { const hook = createRuntimeFallbackHook(createMockPluginInput(), { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 0 }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), }) const sessionID = "test-session-auto-retry-timeout-disabled" @@ -1161,8 +1161,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), } @@ -1212,7 +1212,7 @@ describe("runtime-fallback", () => { "Google Generative AI API key is missing. Pass it using the 'apiKey' parameter or the GOOGLE_GENERATIVE_AI_API_KEY environment variable.", }, }, - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", }, }, }, @@ -1251,8 +1251,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), } @@ -1294,7 +1294,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", status: "Too Many Requests: quota exceeded [retrying in ~2 weeks attempt #1]", }, @@ -1303,8 +1303,8 @@ describe("runtime-fallback", () => { }) expect(retriedModels.length).toBeGreaterThanOrEqual(2) - expect(retriedModels[0]).toBe("github-copilot/claude-opus-4.6") - expect(retriedModels[1]).toBe("anthropic/claude-opus-4-6") + expect(retriedModels[0]).toBe("github-copilot/claude-opus-4.7") + expect(retriedModels[1]).toBe("anthropic/claude-opus-4-7") void sessionErrorPromise }) @@ -1335,8 +1335,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1372,8 +1372,8 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true) const timeoutLog = logCalls.find((c) => c.msg.includes("Session fallback timeout reached")) @@ -1401,8 +1401,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1443,15 +1443,15 @@ describe("runtime-fallback", () => { await hook["chat.message"]?.( { sessionID, - model: { providerID: "github-copilot", modelID: "claude-opus-4.6" }, + model: { providerID: "github-copilot", modelID: "claude-opus-4.7" }, }, output ) await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("should abort in-flight fallback request before advancing on timeout", async () => { @@ -1486,8 +1486,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1524,8 +1524,8 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) expect(abortCalls.some((call) => call.path?.id === sessionID)).toBe(true) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") void sessionErrorPromise }) @@ -1551,8 +1551,8 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", - "anthropic/claude-opus-4-6", + "github-copilot/claude-opus-4.7", + "anthropic/claude-opus-4-7", "openai/gpt-5.4", ]), session_timeout_ms: 20, @@ -1586,7 +1586,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toContain("github-copilot/claude-opus-4.6") + expect(retriedModels).toContain("github-copilot/claude-opus-4.7") await hook.event({ event: { @@ -1624,9 +1624,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1659,7 +1659,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1695,7 +1695,7 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 50)) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) }) test("should not clear fallback timeout on assistant non-error update with Copilot retry signal", async () => { @@ -1719,9 +1719,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1754,7 +1754,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1796,7 +1796,7 @@ describe("runtime-fallback", () => { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1846,7 +1846,7 @@ describe("runtime-fallback", () => { await new Promise((resolve) => setTimeout(resolve, 60)) - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("should not clear fallback timeout on assistant non-error update without user-visible content", async () => { @@ -1870,9 +1870,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1905,7 +1905,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -1914,7 +1914,7 @@ describe("runtime-fallback", () => { info: { sessionID, role: "assistant", - model: "github-copilot/claude-opus-4.6", + model: "github-copilot/claude-opus-4.7", }, }, }, @@ -1946,9 +1946,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -1981,7 +1981,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -2022,9 +2022,9 @@ describe("runtime-fallback", () => { { config: createMockConfig({ notify_on_fallback: false, timeout_seconds: 30 }), pluginConfig: createMockPluginConfigWithCategoryFallback([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]), session_timeout_ms: 20, } @@ -2057,7 +2057,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toEqual(["github-copilot/claude-opus-4.6"]) + expect(retriedModels).toEqual(["github-copilot/claude-opus-4.7"]) await hook.event({ event: { @@ -2145,7 +2145,7 @@ describe("runtime-fallback", () => { }), { config: createMockConfig({ notify_on_fallback: false }), - pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-6"]), + pluginConfig: createMockPluginConfigWithCategoryFallback(["anthropic/claude-opus-4-7"]), } ) @@ -2176,7 +2176,7 @@ describe("runtime-fallback", () => { }, }) - expect(retriedModels).toContain("anthropic/claude-opus-4-6") + expect(retriedModels).toContain("anthropic/claude-opus-4-7") }) test("does NOT trigger fallback for normal type:error-free messages", async () => { @@ -2452,7 +2452,7 @@ describe("runtime-fallback", () => { }), { config: createMockConfig({ notify_on_fallback: false }), - pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", ["github-copilot/claude-opus-4.6"]), + pluginConfig: createMockPluginConfigWithAgentFallback("prometheus", ["github-copilot/claude-opus-4.7"]), }, ) const sessionID = "test-preserve-agent-on-retry" @@ -2462,7 +2462,7 @@ describe("runtime-fallback", () => { type: "session.error", properties: { sessionID, - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", error: { statusCode: 503, message: "Service unavailable" }, agent: "prometheus", }, @@ -2472,7 +2472,7 @@ describe("runtime-fallback", () => { expect(promptCalls.length).toBe(1) const callBody = promptCalls[0]?.body as Record expect(callBody?.agent).toBe("prometheus") - expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.6" }) + expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.7" }) }) }) diff --git a/src/hooks/runtime-fallback/provider-matrix.test.ts b/src/hooks/runtime-fallback/provider-matrix.test.ts index d94986e78..727b2967d 100644 --- a/src/hooks/runtime-fallback/provider-matrix.test.ts +++ b/src/hooks/runtime-fallback/provider-matrix.test.ts @@ -92,7 +92,7 @@ describe("runtime-fallback provider matrix quota tests", () => { //#given const error = { name: "AI_APICallError", - message: "All credentials for model claude-opus-4-6 are cooling down [retrying in ~2 weeks]", + message: "All credentials for model claude-opus-4-7 are cooling down [retrying in ~2 weeks]", provider: "anthropic", } diff --git a/src/hooks/runtime-fallback/retry-model-payload.ts b/src/hooks/runtime-fallback/retry-model-payload.ts index 0c9ed0c9a..d5f59b74c 100644 --- a/src/hooks/runtime-fallback/retry-model-payload.ts +++ b/src/hooks/runtime-fallback/retry-model-payload.ts @@ -1,4 +1,4 @@ -import { parseModelString } from "../../tools/delegate-task/model-string-parser" +import { parseModelString } from "../../shared/model-string-parser" export function buildRetryModelPayload( model: string, diff --git a/src/hooks/runtime-fallback/session-status-handler.test.ts b/src/hooks/runtime-fallback/session-status-handler.test.ts index 42316a6ec..6a7dee7cf 100644 --- a/src/hooks/runtime-fallback/session-status-handler.test.ts +++ b/src/hooks/runtime-fallback/session-status-handler.test.ts @@ -74,12 +74,12 @@ describe("createSessionStatusHandler", () => { const deps = createDeps() const abortCalls: string[] = [] const retryCalls: Array<{ sessionID: string; model: string; source: string }> = [] - const state = createFallbackState("anthropic/claude-opus-4-6") + const state = createFallbackState("anthropic/claude-opus-4-7") state.currentModel = "openai/gpt-5.4" state.fallbackIndex = 0 state.attemptCount = 1 state.pendingFallbackModel = "openai/gpt-5.4" - state.failedModels.set("anthropic/claude-opus-4-6", Date.now()) + state.failedModels.set("anthropic/claude-opus-4-7", Date.now()) deps.sessionStates.set(sessionID, state) const handler = createSessionStatusHandler(deps, createHelpers(abortCalls, retryCalls), deps.sessionStatusRetryKeys) diff --git a/src/hooks/session-notification-event-properties.ts b/src/hooks/session-notification-event-properties.ts new file mode 100644 index 000000000..b51edf81b --- /dev/null +++ b/src/hooks/session-notification-event-properties.ts @@ -0,0 +1,51 @@ +type EventProperties = Record | undefined + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function getEventInfo(properties: EventProperties): Record | undefined { + const info = properties?.info + return isRecord(info) ? info : undefined +} + +export function getSessionID(properties: EventProperties): string | undefined { + const sessionID = properties?.sessionID + if (typeof sessionID === "string" && sessionID.length > 0) return sessionID + + const sessionId = properties?.sessionId + if (typeof sessionId === "string" && sessionId.length > 0) return sessionId + + const info = getEventInfo(properties) + const infoSessionID = info?.sessionID + if (typeof infoSessionID === "string" && infoSessionID.length > 0) return infoSessionID + + const infoSessionId = info?.sessionId + if (typeof infoSessionId === "string" && infoSessionId.length > 0) return infoSessionId + + return undefined +} + +export function getEventToolName(properties: EventProperties): string | undefined { + const tool = properties?.tool + if (typeof tool === "string" && tool.length > 0) return tool + + const name = properties?.name + if (typeof name === "string" && name.length > 0) return name + + return undefined +} + +export function getQuestionText(properties: EventProperties): string { + const args = properties?.args + if (!isRecord(args)) return "" + + const questions = args.questions + if (!Array.isArray(questions) || questions.length === 0) return "" + + const firstQuestion = questions[0] + if (!isRecord(firstQuestion)) return "" + + const questionText = firstQuestion.question + return typeof questionText === "string" ? questionText : "" +} diff --git a/src/hooks/session-notification-init.ts b/src/hooks/session-notification-init.ts new file mode 100644 index 000000000..3dab42ea6 --- /dev/null +++ b/src/hooks/session-notification-init.ts @@ -0,0 +1,31 @@ +import type { Platform } from "./session-notification-sender" +import * as sessionNotificationSender from "./session-notification-sender" +import { startBackgroundCheck } from "./session-notification-utils" + +export function createSessionNotificationInit() { + let platform: Platform | null = null + let defaultSoundPath: string | null = null + let started = false + + function initialize(): { platform: Platform; defaultSoundPath: string } { + if (!platform) { + platform = sessionNotificationSender.detectPlatform() + } + if (!defaultSoundPath) { + defaultSoundPath = sessionNotificationSender.getDefaultSoundPath(platform) + } + if (!started) { + startBackgroundCheck(platform) + started = true + } + + return { + platform, + defaultSoundPath, + } + } + + return { + initialize, + } +} diff --git a/src/hooks/session-notification-input-needed.test.ts b/src/hooks/session-notification-input-needed.test.ts index ee1614b88..f85d9154d 100644 --- a/src/hooks/session-notification-input-needed.test.ts +++ b/src/hooks/session-notification-input-needed.test.ts @@ -93,6 +93,53 @@ describe("session-notification input-needed events", () => { expect(notificationCalls).toHaveLength(1) expect(notificationCalls[0]).toContain("Agent needs permission to continue") }) + + test("lazily detects platform and starts background checks on first idle event", async () => { + const sessionID = "main-idle" + setMainSession(sessionID) + + const detectPlatformSpy = spyOn(sender, "detectPlatform") + detectPlatformSpy.mockReturnValue("darwin") + + const getDefaultSoundPathSpy = spyOn(sender, "getDefaultSoundPath") + getDefaultSoundPathSpy.mockReturnValue("/System/Library/Sounds/Glass.aiff") + + const startBackgroundCheckSpy = spyOn(utils, "startBackgroundCheck") + startBackgroundCheckSpy.mockImplementation(() => {}) + + // given + const hook = createSessionNotification(createMockPluginInput(), { enforceMainSessionFilter: false }) + + // when + await hook({ + event: { + type: "session.idle", + properties: { + sessionID, + }, + }, + }) + + // then + expect(detectPlatformSpy).toHaveBeenCalledTimes(1) + expect(getDefaultSoundPathSpy).toHaveBeenCalledTimes(1) + expect(startBackgroundCheckSpy).toHaveBeenCalledTimes(1) + + // when + await hook({ + event: { + type: "session.idle", + properties: { + sessionID, + }, + }, + }) + + // then + expect(detectPlatformSpy).toHaveBeenCalledTimes(1) + expect(getDefaultSoundPathSpy).toHaveBeenCalledTimes(1) + expect(startBackgroundCheckSpy).toHaveBeenCalledTimes(1) + }) }) export {} diff --git a/src/hooks/session-notification.ts b/src/hooks/session-notification.ts index d54d38c61..f9a40f56d 100644 --- a/src/hooks/session-notification.ts +++ b/src/hooks/session-notification.ts @@ -1,15 +1,12 @@ import type { PluginInput } from "@opencode-ai/plugin" import { subagentSessions, getMainSessionID } from "../features/claude-code-session-state" -import { - startBackgroundCheck, -} from "./session-notification-utils" import { buildReadyNotificationContent } from "./session-notification-content" -import { - type Platform, -} from "./session-notification-sender" +import { type Platform } from "./session-notification-sender" import * as sessionNotificationSender from "./session-notification-sender" +import { getEventToolName, getQuestionText, getSessionID } from "./session-notification-event-properties" import { hasIncompleteTodos } from "./session-todo-status" import { createIdleNotificationScheduler } from "./session-notification-scheduler" +import { createSessionNotificationInit } from "./session-notification-init" interface SessionNotificationConfig { title?: string @@ -28,22 +25,15 @@ interface SessionNotificationConfig { /** Grace period in ms to ignore late-arriving activity events after scheduling (default: 100) */ activityGracePeriodMs?: number } -export function createSessionNotification( - ctx: PluginInput, - config: SessionNotificationConfig = {} -) { - const currentPlatform: Platform = sessionNotificationSender.detectPlatform() - const defaultSoundPath = sessionNotificationSender.getDefaultSoundPath(currentPlatform) - - startBackgroundCheck(currentPlatform) +export function createSessionNotification(ctx: PluginInput, config: SessionNotificationConfig = {}) { const mergedConfig = { title: "OpenCode", message: "Agent is ready for input", questionMessage: "Agent is asking a question", permissionMessage: "Agent needs permission to continue", playSound: false, - soundPath: defaultSoundPath, + soundPath: "", idleConfirmationDelay: 1500, skipIfIncompleteTodos: true, maxTrackedSessions: 100, @@ -51,22 +41,18 @@ export function createSessionNotification( ...config, } + const sessionNotificationInit = createSessionNotificationInit() + let currentPlatform: Platform | null = null + let defaultSoundPath = mergedConfig.soundPath + const scheduler = createIdleNotificationScheduler({ ctx, - platform: currentPlatform, + platform: "unsupported", config: mergedConfig, hasIncompleteTodos, send: async (hookCtx, platform, sessionID) => { - if ( - typeof hookCtx.client.session.get !== "function" - && typeof hookCtx.client.session.messages !== "function" - ) { - await sessionNotificationSender.sendSessionNotification( - hookCtx, - platform, - mergedConfig.title, - mergedConfig.message, - ) + if (typeof hookCtx.client.session.get !== "function" && typeof hookCtx.client.session.messages !== "function") { + await sessionNotificationSender.sendSessionNotification(hookCtx, platform, mergedConfig.title, mergedConfig.message) return } @@ -85,21 +71,13 @@ export function createSessionNotification( const PERMISSION_EVENTS = new Set(["permission.ask", "permission.asked", "permission.updated", "permission.requested"]) const PERMISSION_HINT_PATTERN = /\b(permission|approve|approval|allow|deny|consent)\b/i - const getSessionID = (properties: Record | undefined): string | undefined => { - const sessionID = properties?.sessionID - if (typeof sessionID === "string" && sessionID.length > 0) return sessionID + const ensureNotificationPlatform = (): Platform => { + if (currentPlatform) return currentPlatform - const sessionId = properties?.sessionId - if (typeof sessionId === "string" && sessionId.length > 0) return sessionId - - const info = properties?.info as Record | undefined - const infoSessionID = info?.sessionID - if (typeof infoSessionID === "string" && infoSessionID.length > 0) return infoSessionID - - const infoSessionId = info?.sessionId - if (typeof infoSessionId === "string" && infoSessionId.length > 0) return infoSessionId - - return undefined + const initialized = sessionNotificationInit.initialize() + currentPlatform = initialized.platform + defaultSoundPath = initialized.defaultSoundPath || mergedConfig.soundPath + return currentPlatform } const shouldNotifyForSession = (sessionID: string): boolean => { @@ -113,37 +91,13 @@ export function createSessionNotification( return true } - const getEventToolName = (properties: Record | undefined): string | undefined => { - const tool = properties?.tool - if (typeof tool === "string" && tool.length > 0) return tool - - const name = properties?.name - if (typeof name === "string" && name.length > 0) return name - - return undefined - } - - const getQuestionText = (properties: Record | undefined): string => { - const args = properties?.args as Record | undefined - const questions = args?.questions - if (!Array.isArray(questions) || questions.length === 0) return "" - - const firstQuestion = questions[0] as Record | undefined - const questionText = firstQuestion?.question - return typeof questionText === "string" ? questionText : "" - } - return async ({ event }: { event: { type: string; properties?: unknown } }) => { - if (currentPlatform === "unsupported") return - const props = event.properties as Record | undefined if (event.type === "session.created") { const info = props?.info as Record | undefined const sessionID = info?.id as string | undefined - if (sessionID) { - scheduler.markSessionActivity(sessionID) - } + if (sessionID) scheduler.markSessionActivity(sessionID) return } @@ -151,6 +105,8 @@ export function createSessionNotification( const sessionID = getSessionID(props) if (!sessionID) return + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return scheduler.scheduleIdleNotification(sessionID) @@ -160,26 +116,22 @@ export function createSessionNotification( if (event.type === "message.updated") { const info = props?.info as Record | undefined const sessionID = getSessionID({ ...props, info }) - if (sessionID) { - scheduler.markSessionActivity(sessionID) - } + if (sessionID) scheduler.markSessionActivity(sessionID) return } if (PERMISSION_EVENTS.has(event.type)) { const sessionID = getSessionID(props) if (!sessionID) return + + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return scheduler.markSessionActivity(sessionID) - await sessionNotificationSender.sendSessionNotification( - ctx, - currentPlatform, - mergedConfig.title, - mergedConfig.permissionMessage, - ) - if (mergedConfig.playSound && mergedConfig.soundPath) { - await sessionNotificationSender.playSessionNotificationSound(ctx, currentPlatform, mergedConfig.soundPath) + await sessionNotificationSender.sendSessionNotification(ctx, platform, mergedConfig.title, mergedConfig.permissionMessage) + if (mergedConfig.playSound && defaultSoundPath) { + await sessionNotificationSender.playSessionNotificationSound(ctx, platform, defaultSoundPath) } return } @@ -192,16 +144,16 @@ export function createSessionNotification( if (event.type === "tool.execute.before") { const toolName = getEventToolName(props)?.toLowerCase() if (toolName && QUESTION_TOOLS.has(toolName)) { + const platform = ensureNotificationPlatform() + if (platform === "unsupported") return if (!shouldNotifyForSession(sessionID)) return const questionText = getQuestionText(props) - const message = PERMISSION_HINT_PATTERN.test(questionText) - ? mergedConfig.permissionMessage - : mergedConfig.questionMessage + const message = PERMISSION_HINT_PATTERN.test(questionText) ? mergedConfig.permissionMessage : mergedConfig.questionMessage - await sessionNotificationSender.sendSessionNotification(ctx, currentPlatform, mergedConfig.title, message) - if (mergedConfig.playSound && mergedConfig.soundPath) { - await sessionNotificationSender.playSessionNotificationSound(ctx, currentPlatform, mergedConfig.soundPath) + await sessionNotificationSender.sendSessionNotification(ctx, platform, mergedConfig.title, message) + if (mergedConfig.playSound && defaultSoundPath) { + await sessionNotificationSender.playSessionNotificationSound(ctx, platform, defaultSoundPath) } } } @@ -211,9 +163,7 @@ export function createSessionNotification( if (event.type === "session.deleted") { const sessionInfo = props?.info as { id?: string } | undefined - if (sessionInfo?.id) { - scheduler.deleteSession(sessionInfo.id) - } + if (sessionInfo?.id) scheduler.deleteSession(sessionInfo.id) } } } diff --git a/src/hooks/task-resume-info/hook.ts b/src/hooks/task-resume-info/hook.ts index 1774aef6a..7fda3d640 100644 --- a/src/hooks/task-resume-info/hook.ts +++ b/src/hooks/task-resume-info/hook.ts @@ -1,20 +1,7 @@ +import { extractTaskLink } from "../../features/tool-metadata-store" + const TARGET_TOOLS = ["task", "Task", "task_tool", "call_omo_agent"] -const SESSION_ID_PATTERNS = [ - /Session ID: (ses_[a-zA-Z0-9_-]+)/, - /session_id: (ses_[a-zA-Z0-9_-]+)/, - /\s*session_id: (ses_[a-zA-Z0-9_-]+)/, - /sessionId: (ses_[a-zA-Z0-9_-]+)/, -] - -function extractSessionId(output: string): string | null { - for (const pattern of SESSION_ID_PATTERNS) { - const match = output.match(pattern) - if (match) return match[1] ?? null - } - return null -} - export function createTaskResumeInfoHook() { const toolExecuteAfter = async ( input: { tool: string; sessionID: string; callID: string }, @@ -25,12 +12,13 @@ export function createTaskResumeInfoHook() { if (outputText.startsWith("Error:") || outputText.startsWith("Failed")) return if (outputText.includes("\nto continue:")) return - const sessionId = extractSessionId(outputText) - if (!sessionId) return + const link = extractTaskLink(output.metadata, outputText) + const taskId = link.taskId ?? link.sessionId + if (!taskId) return output.output = outputText.trimEnd() + - `\n\nto continue: task(session_id="${sessionId}", load_skills=[], run_in_background=false, prompt="...")` + `\n\nto continue: task(task_id="${taskId}", load_skills=[], run_in_background=false, prompt="...")` } return { diff --git a/src/hooks/task-resume-info/index.test.ts b/src/hooks/task-resume-info/index.test.ts index 2d10ef757..30708380b 100644 --- a/src/hooks/task-resume-info/index.test.ts +++ b/src/hooks/task-resume-info/index.test.ts @@ -60,6 +60,7 @@ describe("createTaskResumeInfoHook", () => { await afterHook(input, output) expect(output.output).toContain("to continue:") + expect(output.output).toContain('task(task_id="ses_abc123"') expect(output.output).toContain("ses_abc123") }) @@ -74,6 +75,25 @@ describe("createTaskResumeInfoHook", () => { await afterHook(input, output) expect(output.output).toContain("run_in_background=false") + expect(output.output).toContain('task_id="ses_abc123"') + }) + }) + }) + + describe("#given target tool with session metadata object", () => { + describe("#when output text omits session ID but metadata includes it", () => { + it("#then should append resume info from metadata", async () => { + const input = createInput("task") + const output = { + title: "task", + output: "Task completed successfully", + metadata: { sessionID: "ses_meta_123" }, + } + + await afterHook(input, output) + + expect(output.output).toContain("to continue:") + expect(output.output).toContain("ses_meta_123") }) }) }) @@ -102,7 +122,7 @@ describe("createTaskResumeInfoHook", () => { const output = { title: "task", output: - 'Done.\nSession ID: ses_abc123\nto continue: task(session_id="ses_abc123", load_skills=[], prompt="...")', + 'Done.\nSession ID: ses_abc123\nto continue: task(task_id="ses_abc123", load_skills=[], run_in_background=false, prompt="...")', metadata: {}, } diff --git a/src/hooks/think-mode/index.test.ts b/src/hooks/think-mode/index.test.ts index 34c1ba55c..f85763608 100644 --- a/src/hooks/think-mode/index.test.ts +++ b/src/hooks/think-mode/index.test.ts @@ -49,7 +49,7 @@ describe("createThinkModeHook", () => { const input = createHookInput({ sessionID, providerID: "github-copilot", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) const output = createHookOutput("Please think deeply about this") diff --git a/src/hooks/think-mode/switcher.test.ts b/src/hooks/think-mode/switcher.test.ts index bbe01bed6..b462e76ff 100644 --- a/src/hooks/think-mode/switcher.test.ts +++ b/src/hooks/think-mode/switcher.test.ts @@ -23,26 +23,26 @@ describe("think-mode switcher", () => { describe("getHighVariant with dots vs hyphens", () => { it("should handle dots in Claude version numbers", () => { // given a Claude model ID with dot format - const variant = getHighVariant("claude-opus-4.6") + const variant = getHighVariant("claude-opus-4.7") // then should return high variant with hyphen format - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) it("should handle hyphens in Claude version numbers", () => { // given a Claude model ID with hyphen format - const variant = getHighVariant("claude-opus-4-6") + const variant = getHighVariant("claude-opus-4-7") // then should return high variant - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) - it("should handle claude-opus-4-6 high variant", () => { - // given a Claude Opus 4.6 model ID - const variant = getHighVariant("claude-opus-4-6") + it("should handle claude-opus-4-7 high variant", () => { + // given a Claude Opus 4.7 model ID + const variant = getHighVariant("claude-opus-4-7") // then should return high variant - expect(variant).toBe("claude-opus-4-6-high") + expect(variant).toBe("claude-opus-4-7-high") }) it("should handle dots in GPT version numbers", () => { @@ -73,7 +73,7 @@ describe("think-mode switcher", () => { it("should return null for already-high variants", () => { // given model IDs that are already high variants - expect(getHighVariant("claude-opus-4-6-high")).toBeNull() + expect(getHighVariant("claude-opus-4-7-high")).toBeNull() expect(getHighVariant("gpt-5-4-high")).toBeNull() expect(getHighVariant("gemini-3-1-pro-high")).toBeNull() }) @@ -89,7 +89,7 @@ describe("think-mode switcher", () => { describe("isAlreadyHighVariant", () => { it("should detect -high suffix", () => { // given model IDs with -high suffix - expect(isAlreadyHighVariant("claude-opus-4-6-high")).toBe(true) + expect(isAlreadyHighVariant("claude-opus-4-7-high")).toBe(true) expect(isAlreadyHighVariant("gpt-5-4-high")).toBe(true) expect(isAlreadyHighVariant("gemini-3.1-pro-high")).toBe(true) }) @@ -101,8 +101,8 @@ describe("think-mode switcher", () => { it("should return false for base models", () => { // given base model IDs without -high suffix - expect(isAlreadyHighVariant("claude-opus-4-6")).toBe(false) - expect(isAlreadyHighVariant("claude-opus-4.6")).toBe(false) + expect(isAlreadyHighVariant("claude-opus-4-7")).toBe(false) + expect(isAlreadyHighVariant("claude-opus-4.7")).toBe(false) expect(isAlreadyHighVariant("gpt-5.4")).toBe(false) expect(isAlreadyHighVariant("gemini-3.1-pro")).toBe(false) }) @@ -133,10 +133,10 @@ describe("think-mode switcher", () => { it("should handle prefixes with dots in version numbers", () => { // given a model ID with prefix and dots - const variant = getHighVariant("vertex_ai/claude-opus-4.6") + const variant = getHighVariant("vertex_ai/claude-opus-4.7") // then should normalize dots and preserve prefix - expect(variant).toBe("vertex_ai/claude-opus-4-6-high") + expect(variant).toBe("vertex_ai/claude-opus-4-7-high") }) it("should handle multiple different prefixes", () => { @@ -167,7 +167,7 @@ describe("think-mode switcher", () => { it("should return null for already-high prefixed models", () => { // given prefixed model IDs that are already high - expect(getHighVariant("vertex_ai/claude-opus-4-6-high")).toBeNull() + expect(getHighVariant("vertex_ai/claude-opus-4-7-high")).toBeNull() expect(getHighVariant("openai/gpt-5-4-high")).toBeNull() }) }) @@ -175,14 +175,14 @@ describe("think-mode switcher", () => { describe("isAlreadyHighVariant with prefixes", () => { it("should detect -high suffix in prefixed models", () => { // given prefixed model IDs with -high suffix - expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-6-high")).toBe(true) + expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-7-high")).toBe(true) expect(isAlreadyHighVariant("openai/gpt-5-4-high")).toBe(true) expect(isAlreadyHighVariant("custom/gemini-3.1-pro-high")).toBe(true) }) it("should return false for prefixed base models", () => { // given prefixed base model IDs without -high suffix - expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-6")).toBe(false) + expect(isAlreadyHighVariant("vertex_ai/claude-opus-4-7")).toBe(false) expect(isAlreadyHighVariant("openai/gpt-5-4")).toBe(false) }) diff --git a/src/hooks/think-mode/switcher.ts b/src/hooks/think-mode/switcher.ts index 66aa39f5a..8be017d69 100644 --- a/src/hooks/think-mode/switcher.ts +++ b/src/hooks/think-mode/switcher.ts @@ -45,7 +45,7 @@ function extractModelPrefix(modelID: string): { prefix: string; base: string } { const HIGH_VARIANT_MAP: Record = { // Claude "claude-sonnet-4-6": "claude-sonnet-4-6-high", - "claude-opus-4-6": "claude-opus-4-6-high", + "claude-opus-4-7": "claude-opus-4-7-high", // Gemini "gemini-3-1-pro": "gemini-3-1-pro-high", "gemini-3-1-pro-low": "gemini-3-1-pro-high", diff --git a/src/hooks/todo-continuation-enforcer/dispose.test.ts b/src/hooks/todo-continuation-enforcer/dispose.test.ts index 5423c8068..37971bc6d 100644 --- a/src/hooks/todo-continuation-enforcer/dispose.test.ts +++ b/src/hooks/todo-continuation-enforcer/dispose.test.ts @@ -8,6 +8,7 @@ declare module "bun:test" { import { afterAll, afterEach, describe, expect, it, mock } from "bun:test" +import type { BackgroundManager } from "../../features/background-agent" import * as actualSessionStateModule from "./session-state" import type { SessionStateStore } from "./session-state" @@ -37,6 +38,12 @@ function createMockPluginInput(): PluginInput { } as PluginInput } +function createMockBackgroundManager(): BackgroundManager { + return { + getTasksByParentSession: () => [{ status: "running" }], + } as BackgroundManager +} + function getCreatedSessionStateStore(): SessionStateStore { if (!createdSessionStateStore) { throw new Error("expected session state store to be created") @@ -68,7 +75,7 @@ describe("todo-continuation-enforcer dispose", () => { enforcer.dispose() }) - it("#given enforcer with active session states #when dispose is called #then internal session state store is shut down", () => { + it("#given enforcer with active session states #when dispose is called #then internal session state store is shut down", async () => { // given const originalClearInterval = globalThis.clearInterval const clearIntervalCalls: Array[0]> = [] @@ -78,9 +85,13 @@ describe("todo-continuation-enforcer dispose", () => { }) as typeof clearInterval try { - const enforcer = createTodoContinuationEnforcer(createMockPluginInput()) + const enforcer = createTodoContinuationEnforcer(createMockPluginInput(), { + backgroundManager: createMockBackgroundManager(), + }) const sessionStateStore = getCreatedSessionStateStore() + await enforcer.handler({ event: { type: "session.idle", properties: { sessionID: "session-1" } } }) + enforcer.markRecovering("session-1") enforcer.markRecovering("session-2") diff --git a/src/hooks/todo-continuation-enforcer/handler.ts b/src/hooks/todo-continuation-enforcer/handler.ts index 3347ee666..7136dda44 100644 --- a/src/hooks/todo-continuation-enforcer/handler.ts +++ b/src/hooks/todo-continuation-enforcer/handler.ts @@ -61,6 +61,7 @@ export function createTodoContinuationHandler(args: { const sessionID = props?.sessionID as string | undefined if (!sessionID) return + sessionStateStore.startPruneInterval() await handleSessionIdle({ ctx, sessionID, diff --git a/src/hooks/todo-continuation-enforcer/session-state.ts b/src/hooks/todo-continuation-enforcer/session-state.ts index a87472b7a..dcd88629e 100644 --- a/src/hooks/todo-continuation-enforcer/session-state.ts +++ b/src/hooks/todo-continuation-enforcer/session-state.ts @@ -31,6 +31,7 @@ export interface ContinuationProgressUpdate { export interface SessionStateStore { getState: (sessionID: string) => SessionState getExistingState: (sessionID: string) => SessionState | undefined + startPruneInterval: () => void recordActivity: (sessionID: string) => void trackContinuationProgress: ( sessionID: string, @@ -76,18 +77,26 @@ export function createSessionStateStore(): SessionStateStore { // Periodic pruning of stale session states to prevent unbounded Map growth let pruneInterval: TimerHandle | undefined - pruneInterval = setInterval(() => { - const now = Date.now() - for (const [sessionID, tracked] of sessions.entries()) { - if (now - tracked.lastAccessedAt > SESSION_STATE_TTL_MS) { - cancelCountdown(sessionID) - sessions.delete(sessionID) - } + let pruneIntervalStarted = false + + function startPruneInterval(): void { + if (pruneIntervalStarted) { + return + } + + pruneIntervalStarted = true + pruneInterval = setInterval(() => { + const now = Date.now() + for (const [sessionID, tracked] of sessions.entries()) { + if (now - tracked.lastAccessedAt > SESSION_STATE_TTL_MS) { + cancelCountdown(sessionID) + sessions.delete(sessionID) + } + } + }, SESSION_STATE_PRUNE_INTERVAL_MS) + if (typeof pruneInterval === "object" && typeof pruneInterval.unref === "function") { + pruneInterval.unref() } - }, SESSION_STATE_PRUNE_INTERVAL_MS) - // Allow process to exit naturally even if interval is running - if (typeof pruneInterval === "object" && typeof pruneInterval.unref === "function") { - pruneInterval.unref() } function getTrackedSession(sessionID: string): TrackedSessionState { @@ -272,6 +281,7 @@ export function createSessionStateStore(): SessionStateStore { return { getState, getExistingState, + startPruneInterval, recordActivity, trackContinuationProgress, resetContinuationProgress, diff --git a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts index 9c5a35f5c..5315b0842 100644 --- a/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts +++ b/src/hooks/todo-continuation-enforcer/todo-continuation-enforcer.test.ts @@ -249,6 +249,33 @@ describe("todo-continuation-enforcer", () => { _resetForTesting() }) + test("given the first idle event, starts the prune interval lazily", async () => { + // given + const originalSetInterval = globalThis.setInterval + let setIntervalCalls = 0 + globalThis.setInterval = ((callback: TimerCallback, delay?: number, ...args: any[]) => { + setIntervalCalls += 1 + return originalSetInterval(callback, delay, ...args) + }) as typeof setInterval + + try { + const sessionID = "main-lazy-prune" + setMainSession(sessionID) + const hook = createTodoContinuationEnforcer(createMockPluginInput(), { + backgroundManager: createMockBackgroundManager(true), + }) + + // when + await hook.handler({ event: { type: "session.idle", properties: { sessionID } } }) + await hook.handler({ event: { type: "session.idle", properties: { sessionID } } }) + + // then + expect(setIntervalCalls).toBe(1) + } finally { + globalThis.setInterval = originalSetInterval + } + }) + test("should inject continuation when idle with incomplete todos", async () => { fakeTimers.restore() // given - main session with incomplete todos diff --git a/src/hooks/write-existing-file-guard/hook.ts b/src/hooks/write-existing-file-guard/hook.ts index bdaf5cad8..ab7bd9aef 100644 --- a/src/hooks/write-existing-file-guard/hook.ts +++ b/src/hooks/write-existing-file-guard/hook.ts @@ -76,7 +76,15 @@ export function isOverwriteEnabled(value: boolean | string | undefined): boolean export function createWriteExistingFileGuardHook(ctx: PluginInput): Hooks { const readPermissionsBySession = new Map>() const sessionLastAccess = new Map() - const canonicalSessionRoot = toCanonicalPath(resolveInputPath(ctx, ctx.directory)) + let canonicalSessionRoot: string | undefined + + function getCanonicalSessionRoot(): string { + if (!canonicalSessionRoot) { + canonicalSessionRoot = toCanonicalPath(resolveInputPath(ctx, ctx.directory)) + } + + return canonicalSessionRoot + } return { "tool.execute.before": async (input, output) => { @@ -86,7 +94,7 @@ export function createWriteExistingFileGuardHook(ctx: PluginInput): Hooks { output, readPermissionsBySession, sessionLastAccess, - canonicalSessionRoot, + getCanonicalSessionRoot, maxTrackedSessions: MAX_TRACKED_SESSIONS, }) }, diff --git a/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts new file mode 100644 index 000000000..0f1d4bb88 --- /dev/null +++ b/src/hooks/write-existing-file-guard/lazy-canonical-path-init.test.ts @@ -0,0 +1,65 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" + +const realFs = await import("node:fs") + +const existsSyncMock = mock(realFs.existsSync) +const realpathNativeMock = mock(realFs.realpathSync.native) + +mock.module("fs", () => ({ + ...realFs, + existsSync: existsSyncMock, + realpathSync: { + ...realFs.realpathSync, + native: realpathNativeMock, + }, +})) + +const { createWriteExistingFileGuardHook } = await import("./index") + +describe("createWriteExistingFileGuardHook", () => { + let tempDir = "" + + beforeEach(() => { + // given + tempDir = mkdtempSync(join(tmpdir(), "write-existing-file-guard-lazy-")) + mkdirSync(tempDir, { recursive: true }) + existsSyncMock.mockClear() + realpathNativeMock.mockClear() + }) + + afterEach(() => { + rmSync(tempDir, { recursive: true, force: true }) + }) + + test("#given hook factory #when created #then defers fs canonical path calls until first tool invocation", async () => { + // given + const existingFile = join(tempDir, "existing.txt") + writeFileSync(existingFile, "content") + + // when + const hook = createWriteExistingFileGuardHook({ directory: tempDir } as never) + + // then + expect(existsSyncMock).toHaveBeenCalledTimes(0) + expect(realpathNativeMock).toHaveBeenCalledTimes(0) + + // when + await expect( + hook["tool.execute.before"]?.( + { + tool: "write", + sessionID: "ses_lazy", + callID: "call_lazy", + } as never, + { args: { filePath: existingFile, content: "updated" } } as never, + ), + ).rejects.toThrow("File already exists. Use edit tool instead.") + + // then + expect(existsSyncMock).toHaveBeenCalledTimes(3) + expect(realpathNativeMock).toHaveBeenCalledTimes(2) + }) +}) diff --git a/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts b/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts index 25eebbda3..848238a8a 100644 --- a/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts +++ b/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts @@ -90,10 +90,10 @@ export async function handleWriteExistingFileGuardToolExecuteBefore(params: { output: { args?: unknown } readPermissionsBySession: Map> sessionLastAccess: Map - canonicalSessionRoot: string + getCanonicalSessionRoot: () => string maxTrackedSessions: number }): Promise { - const { ctx, input, output, readPermissionsBySession, sessionLastAccess, canonicalSessionRoot, maxTrackedSessions } = params + const { ctx, input, output, readPermissionsBySession, sessionLastAccess, getCanonicalSessionRoot, maxTrackedSessions } = params const toolName = input.tool?.toLowerCase() if (toolName !== "write" && toolName !== "read") { return @@ -107,6 +107,7 @@ export async function handleWriteExistingFileGuardToolExecuteBefore(params: { } const resolvedPath = resolveInputPath(ctx, filePath) + const canonicalSessionRoot = getCanonicalSessionRoot() const canonicalPath = toCanonicalPath(resolvedPath) if (!isPathInsideDirectory(canonicalPath, canonicalSessionRoot)) { return diff --git a/src/hooks/zauc-mocks-hook/hook.test.ts b/src/hooks/zauc-mocks-hook/hook.test.ts index 2c291b1f0..de0e4d3d2 100644 --- a/src/hooks/zauc-mocks-hook/hook.test.ts +++ b/src/hooks/zauc-mocks-hook/hook.test.ts @@ -1,5 +1,13 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" -import { createAutoUpdateCheckerHook } from "../auto-update-checker/hook" + +let scheduledDeferredCheck: (() => void) | null = null +mock.module("../auto-update-checker/hook/deferred-startup-check", () => ({ + scheduleDeferredStartupCheck: (runCheck: () => void) => { + scheduledDeferredCheck = runCheck + }, +})) + +const { createAutoUpdateCheckerHook } = await import("../auto-update-checker/hook") const mockShowConfigErrorsIfAny = mock(async () => {}) const mockShowModelCacheWarningIfNeeded = mock(async () => {}) @@ -38,6 +46,12 @@ function runSessionCreatedEvent( }) } +function drainDeferredCheck(): void { + const run = scheduledDeferredCheck + scheduledDeferredCheck = null + run?.() +} + beforeEach(() => { mockShowConfigErrorsIfAny.mockClear() mockShowModelCacheWarningIfNeeded.mockClear() @@ -51,6 +65,8 @@ beforeEach(() => { mockGetCachedVersion.mockReturnValue("3.6.0") mockGetLocalDevVersion.mockReturnValue(null) + + scheduledDeferredCheck = null }) afterEach(() => { @@ -108,8 +124,9 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives on primary session + //#when - session.created schedules work and deferred check drains it runSessionCreatedEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - startup checks, toast, and background check run @@ -165,9 +182,10 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event is fired twice + //#when - session.created fires twice and deferred check drains once runSessionCreatedEvent(hook) runSessionCreatedEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - side effects execute only once @@ -195,8 +213,9 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives + //#when - session.created schedules and deferred check drains runSessionCreatedEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - local dev toast is shown and background check is skipped @@ -259,8 +278,9 @@ describe("createAutoUpdateCheckerHook", () => { log: () => {}, }) - //#when - session.created event arrives + //#when - session.created schedules and deferred check drains runSessionCreatedEvent(hook) + drainDeferredCheck() await flushScheduledWork() //#then - startup toast includes sisyphus wording diff --git a/src/index.compacting.test.ts b/src/index.compacting.test.ts new file mode 100644 index 000000000..46434d8cb --- /dev/null +++ b/src/index.compacting.test.ts @@ -0,0 +1,136 @@ +import { describe, expect, it, mock } from "bun:test" + +function createCompactingHandler(hooks: { + compactionContextInjector?: { + capture: (sessionID: string) => Promise + inject: (sessionID: string) => string + } + compactionTodoPreserver?: { capture: (sessionID: string) => Promise } + claudeCodeHooks?: { + "experimental.session.compacting"?: ( + input: { sessionID: string }, + output: { context: string[] }, + ) => Promise + } +}) { + return async ( + input: { sessionID: string }, + output: { context: string[] }, + ): Promise => { + await hooks.compactionContextInjector?.capture(input.sessionID) + await hooks.compactionTodoPreserver?.capture(input.sessionID) + await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( + input, + output, + ) + if (hooks.compactionContextInjector) { + output.context.push(hooks.compactionContextInjector.inject(input.sessionID)) + } + } +} + +describe("experimental.session.compacting handler", () => { + //#given all three hooks are present + //#when compacting handler is invoked + //#then all hooks are called in order: capture → PreCompact → contextInjector + it("calls claudeCodeHooks PreCompact alongside other hooks", async () => { + const callOrder: string[] = [] + + const handler = createCompactingHandler({ + compactionContextInjector: { + capture: mock(async () => { + callOrder.push("checkpointCapture") + }), + inject: mock((sessionID: string) => { + callOrder.push("contextInjector") + return `context-for-${sessionID}` + }), + }, + compactionTodoPreserver: { + capture: mock(async () => { + callOrder.push("capture") + }), + }, + claudeCodeHooks: { + "experimental.session.compacting": mock(async () => { + callOrder.push("preCompact") + }), + }, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(callOrder).toEqual([ + "checkpointCapture", + "capture", + "preCompact", + "contextInjector", + ]) + expect(output.context).toEqual(["context-for-ses_test"]) + }) + + //#given claudeCodeHooks injects context during PreCompact + //#when compacting handler is invoked + //#then injected context from PreCompact is preserved in output + it("preserves context injected by PreCompact hooks", async () => { + const handler = createCompactingHandler({ + claudeCodeHooks: { + "experimental.session.compacting": async (_input, output) => { + output.context.push("precompact-injected-context") + }, + }, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(output.context).toContain("precompact-injected-context") + }) + + //#given claudeCodeHooks is null (no claude code hooks configured) + //#when compacting handler is invoked + //#then handler completes without error and other hooks still run + it("handles null claudeCodeHooks gracefully", async () => { + const captureMock = mock(async () => {}) + const checkpointCaptureMock = mock(async () => {}) + const contextMock = mock(() => "injected-context") + + const handler = createCompactingHandler({ + compactionContextInjector: { + capture: checkpointCaptureMock, + inject: contextMock, + }, + compactionTodoPreserver: { capture: captureMock }, + claudeCodeHooks: undefined, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(checkpointCaptureMock).toHaveBeenCalledWith("ses_test") + expect(captureMock).toHaveBeenCalledWith("ses_test") + expect(contextMock).toHaveBeenCalledWith("ses_test") + expect(output.context).toEqual(["injected-context"]) + }) + + //#given compactionContextInjector is null + //#when compacting handler is invoked + //#then handler does not early-return, PreCompact hooks still execute + it("does not early-return when compactionContextInjector is null", async () => { + const preCompactMock = mock(async () => {}) + + const handler = createCompactingHandler({ + claudeCodeHooks: { + "experimental.session.compacting": preCompactMock, + }, + compactionContextInjector: undefined, + }) + + const output = { context: [] as string[] } + await handler({ sessionID: "ses_test" }, output) + + expect(preCompactMock).toHaveBeenCalled() + expect(output.context).toEqual([]) + }) +}) diff --git a/src/index.compaction-model-agnostic.static.test.ts b/src/index.compaction-model-agnostic.static.test.ts index ccba44101..6dfacb6f3 100644 --- a/src/index.compaction-model-agnostic.static.test.ts +++ b/src/index.compaction-model-agnostic.static.test.ts @@ -13,7 +13,7 @@ describe("experimental.session.compacting", () => { //#then expect(hookIndex).toBeGreaterThanOrEqual(0) - expect(content.includes('modelID: "claude-opus-4-6"')).toBe(false) + expect(content.includes('modelID: "claude-opus-4-7"')).toBe(false) expect(hookSlice.includes("output.context.push")).toBe(true) expect(hookSlice.includes("providerID:")).toBe(false) expect(hookSlice.includes("modelID:")).toBe(false) diff --git a/src/index.conditional-tools.test.ts b/src/index.conditional-tools.test.ts new file mode 100644 index 000000000..96c955c4b --- /dev/null +++ b/src/index.conditional-tools.test.ts @@ -0,0 +1,85 @@ +import { describe, expect, it } from "bun:test" + +describe("look_at tool conditional registration", () => { + describe("isMultimodalLookerEnabled logic", () => { + // given multimodal-looker is in disabled_agents + // when checking if agent is enabled + // then should return false (disabled) + it("returns false when multimodal-looker is disabled (exact case)", () => { + const disabledAgents: string[] = ["multimodal-looker"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(false) + }) + + // given multimodal-looker is in disabled_agents with different case + // when checking if agent is enabled + // then should return false (case-insensitive match) + it("returns false when multimodal-looker is disabled (case-insensitive)", () => { + const disabledAgents: string[] = ["Multimodal-Looker"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(false) + }) + + // given multimodal-looker is NOT in disabled_agents + // when checking if agent is enabled + // then should return true (enabled) + it("returns true when multimodal-looker is not disabled", () => { + const disabledAgents: string[] = ["oracle", "librarian"] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + + // given disabled_agents is empty + // when checking if agent is enabled + // then should return true (enabled by default) + it("returns true when disabled_agents is empty", () => { + const disabledAgents: string[] = [] + const isEnabled = !disabledAgents.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + + // given disabled_agents is undefined (simulated as empty array) + // when checking if agent is enabled + // then should return true (enabled by default) + it("returns true when disabled_agents is undefined (fallback to empty)", () => { + const disabledAgents: string[] | undefined = undefined + const list: string[] = disabledAgents ?? [] + const isEnabled = !list.some( + (agent) => agent.toLowerCase() === "multimodal-looker", + ) + expect(isEnabled).toBe(true) + }) + }) + + describe("conditional tool spread pattern", () => { + // given lookAt is not null (agent enabled) + // when spreading into tool object + // then look_at should be included + it("includes look_at when lookAt is not null", () => { + const lookAt = { execute: () => {} } + const tools = { + ...(lookAt ? { look_at: lookAt } : {}), + } + expect(tools).toHaveProperty("look_at") + }) + + // given lookAt is null (agent disabled) + // when spreading into tool object + // then look_at should NOT be included + it("excludes look_at when lookAt is null", () => { + const lookAt = null + const tools = { + ...(lookAt ? { look_at: lookAt } : {}), + } + expect(tools).not.toHaveProperty("look_at") + }) + }) +}) diff --git a/src/index.telemetry.test.ts b/src/index.telemetry.test.ts index f3026a1cb..924a7db2c 100644 --- a/src/index.telemetry.test.ts +++ b/src/index.telemetry.test.ts @@ -29,7 +29,6 @@ const mockCreateHooks = mock(() => ({ compactionTodoPreserver: undefined, claudeCodeHooks: undefined, })) -const mockCreatePluginDispose = mock(() => async () => {}) const mockCreatePluginInterface = mock(() => ({})) const mockCreatePluginPostHog = mock(() => ({ trackActive: () => { @@ -70,9 +69,6 @@ function installModuleMocks(): void { mock.module("./create-hooks", () => ({ createHooks: mockCreateHooks, })) - mock.module("./plugin-dispose", () => ({ - createPluginDispose: mockCreatePluginDispose, - })) mock.module("./plugin-interface", () => ({ createPluginInterface: mockCreatePluginInterface, })) @@ -110,7 +106,7 @@ function installModuleMocks(): void { })) } -describe("OhMyOpenCodePlugin telemetry isolation", () => { +describe("oh-my-openagent telemetry isolation", () => { beforeEach(() => { mock.restore() installModuleMocks() @@ -125,12 +121,13 @@ describe("OhMyOpenCodePlugin telemetry isolation", () => { const { default: plugin } = await import(`./index?telemetry=${Date.now()}-${Math.random()}`) // when - const result = await plugin({ + const result = await plugin.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then - expect(result).toMatchObject({ name: "oh-my-openagent" }) + expect(typeof result).toBe("object") + expect(result).not.toBeNull() }) }) diff --git a/src/index.test.ts b/src/index.test.ts index 7101b9f09..ba7be1363 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,223 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" -describe("experimental.session.compacting handler", () => { - function createCompactingHandler(hooks: { - compactionContextInjector?: { - capture: (sessionID: string) => Promise - inject: (sessionID: string) => string - } - compactionTodoPreserver?: { capture: (sessionID: string) => Promise } - claudeCodeHooks?: { - "experimental.session.compacting"?: ( - input: { sessionID: string }, - output: { context: string[] }, - ) => Promise - } - }) { - return async ( - _input: { sessionID: string }, - output: { context: string[] }, - ): Promise => { - await hooks.compactionContextInjector?.capture(_input.sessionID) - await hooks.compactionTodoPreserver?.capture(_input.sessionID) - await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( - _input, - output, - ) - if (hooks.compactionContextInjector) { - output.context.push(hooks.compactionContextInjector.inject(_input.sessionID)) - } - } - } - - //#given all three hooks are present - //#when compacting handler is invoked - //#then all hooks are called in order: capture → PreCompact → contextInjector - it("calls claudeCodeHooks PreCompact alongside other hooks", async () => { - const callOrder: string[] = [] - - const handler = createCompactingHandler({ - compactionContextInjector: { - capture: mock(async () => { - callOrder.push("checkpointCapture") - }), - inject: mock((sessionID: string) => { - callOrder.push("contextInjector") - return `context-for-${sessionID}` - }), - }, - compactionTodoPreserver: { - capture: mock(async () => { callOrder.push("capture") }), - }, - claudeCodeHooks: { - "experimental.session.compacting": mock(async () => { - callOrder.push("preCompact") - }), - }, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(callOrder).toEqual(["checkpointCapture", "capture", "preCompact", "contextInjector"]) - expect(output.context).toEqual(["context-for-ses_test"]) - }) - - //#given claudeCodeHooks injects context during PreCompact - //#when compacting handler is invoked - //#then injected context from PreCompact is preserved in output - it("preserves context injected by PreCompact hooks", async () => { - const handler = createCompactingHandler({ - claudeCodeHooks: { - "experimental.session.compacting": async (_input, output) => { - output.context.push("precompact-injected-context") - }, - }, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(output.context).toContain("precompact-injected-context") - }) - - //#given claudeCodeHooks is null (no claude code hooks configured) - //#when compacting handler is invoked - //#then handler completes without error and other hooks still run - it("handles null claudeCodeHooks gracefully", async () => { - const captureMock = mock(async () => {}) - const checkpointCaptureMock = mock(async () => {}) - const contextMock = mock(() => "injected-context") - - const handler = createCompactingHandler({ - compactionContextInjector: { - capture: checkpointCaptureMock, - inject: contextMock, - }, - compactionTodoPreserver: { capture: captureMock }, - claudeCodeHooks: undefined, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(checkpointCaptureMock).toHaveBeenCalledWith("ses_test") - expect(captureMock).toHaveBeenCalledWith("ses_test") - expect(contextMock).toHaveBeenCalledWith("ses_test") - expect(output.context).toEqual(["injected-context"]) - }) - - //#given compactionContextInjector is null - //#when compacting handler is invoked - //#then handler does not early-return, PreCompact hooks still execute - it("does not early-return when compactionContextInjector is null", async () => { - const preCompactMock = mock(async () => {}) - - const handler = createCompactingHandler({ - claudeCodeHooks: { - "experimental.session.compacting": preCompactMock, - }, - compactionContextInjector: undefined, - }) - - const output = { context: [] as string[] } - await handler({ sessionID: "ses_test" }, output) - - expect(preCompactMock).toHaveBeenCalled() - expect(output.context).toEqual([]) - }) -}) - -/** - * Tests for conditional tool registration logic in index.ts - * - * The actual plugin initialization is complex to test directly, - * so we test the underlying logic that determines tool registration. - */ -describe("look_at tool conditional registration", () => { - describe("isMultimodalLookerEnabled logic", () => { - // given multimodal-looker is in disabled_agents - // when checking if agent is enabled - // then should return false (disabled) - it("returns false when multimodal-looker is disabled (exact case)", () => { - const disabledAgents: string[] = ["multimodal-looker"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(false) - }) - - // given multimodal-looker is in disabled_agents with different case - // when checking if agent is enabled - // then should return false (case-insensitive match) - it("returns false when multimodal-looker is disabled (case-insensitive)", () => { - const disabledAgents: string[] = ["Multimodal-Looker"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(false) - }) - - // given multimodal-looker is NOT in disabled_agents - // when checking if agent is enabled - // then should return true (enabled) - it("returns true when multimodal-looker is not disabled", () => { - const disabledAgents: string[] = ["oracle", "librarian"] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - - // given disabled_agents is empty - // when checking if agent is enabled - // then should return true (enabled by default) - it("returns true when disabled_agents is empty", () => { - const disabledAgents: string[] = [] - const isEnabled = !disabledAgents.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - - // given disabled_agents is undefined (simulated as empty array) - // when checking if agent is enabled - // then should return true (enabled by default) - it("returns true when disabled_agents is undefined (fallback to empty)", () => { - const disabledAgents: string[] | undefined = undefined - const list: string[] = disabledAgents ?? [] - const isEnabled = !list.some( - (agent) => agent.toLowerCase() === "multimodal-looker" - ) - expect(isEnabled).toBe(true) - }) - }) - - describe("conditional tool spread pattern", () => { - // given lookAt is not null (agent enabled) - // when spreading into tool object - // then look_at should be included - it("includes look_at when lookAt is not null", () => { - const lookAt = { execute: () => {} } // mock tool - const tools = { - ...(lookAt ? { look_at: lookAt } : {}), - } - expect(tools).toHaveProperty("look_at") - }) - - // given lookAt is null (agent disabled) - // when spreading into tool object - // then look_at should NOT be included - it("excludes look_at when lookAt is null", () => { - const lookAt = null - const tools = { - ...(lookAt ? { look_at: lookAt } : {}), - } - expect(tools).not.toHaveProperty("look_at") - }) - }) -}) - const mockInitConfigContext = mock(() => {}) const mockDetectExternalSkillPlugin = mock(() => ({ detected: false, pluginName: null })) const mockGetSkillPluginConflictWarning = mock(() => "") @@ -252,12 +34,11 @@ const mockCreateHooks = mock(() => ({ compactionTodoPreserver: undefined, claudeCodeHooks: undefined, })) -const mockCreatePluginDispose = mock(() => async () => {}) const mockCreatePluginInterface = mock(() => ({})) const mockInitializeOpenClaw = mock(async () => {}) const mockStartTmuxCheck = mock(() => {}) -let OhMyOpenCodePlugin: (typeof import("./index"))["default"] +let pluginModule: (typeof import("./index"))["default"] function installIndexModuleMocks(): void { mock.module("./cli/config-manager/config-context", () => ({ @@ -297,10 +78,6 @@ function installIndexModuleMocks(): void { createHooks: mockCreateHooks, })) - mock.module("./plugin-dispose", () => ({ - createPluginDispose: mockCreatePluginDispose, - })) - mock.module("./plugin-interface", () => ({ createPluginInterface: mockCreatePluginInterface, })) @@ -333,11 +110,11 @@ async function importFreshIndexModule(): Promise { return import(`./index?test=${Date.now()}-${Math.random()}`) } -describe("OhMyOpenCodePlugin", () => { +describe("oh-my-openagent plugin module", () => { beforeEach(async () => { mock.restore() installIndexModuleMocks() - ;({ default: OhMyOpenCodePlugin } = await importFreshIndexModule()) + ;({ default: pluginModule } = await importFreshIndexModule()) mockInitConfigContext.mockClear() mockDetectExternalSkillPlugin.mockClear() mockGetSkillPluginConflictWarning.mockClear() @@ -350,7 +127,6 @@ describe("OhMyOpenCodePlugin", () => { mockCreateManagers.mockClear() mockCreateTools.mockClear() mockCreateHooks.mockClear() - mockCreatePluginDispose.mockClear() mockCreatePluginInterface.mockClear() mockInitializeOpenClaw.mockClear() mockStartTmuxCheck.mockClear() @@ -375,10 +151,10 @@ describe("OhMyOpenCodePlugin", () => { }) // when - await OhMyOpenCodePlugin({ + await pluginModule.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then expect(mockInitializeOpenClaw).toHaveBeenCalledTimes(1) @@ -390,12 +166,21 @@ describe("OhMyOpenCodePlugin", () => { mockLoadPluginConfig.mockReturnValue({}) // when - await OhMyOpenCodePlugin({ + await pluginModule.server({ directory: "/tmp/project", client: {}, - } as Parameters[0]) + } as Parameters[0]) // then expect(mockInitializeOpenClaw).not.toHaveBeenCalled() }) + + it("exports a V1 PluginModule shape with id and server", () => { + // given the plugin module is loaded + // when inspecting the default export + // then it has the expected V1 shape + expect(typeof pluginModule).toBe("object") + expect(pluginModule.id).toBe("oh-my-openagent") + expect(typeof pluginModule.server).toBe("function") + }) }) diff --git a/src/index.ts b/src/index.ts index b36e6c4b9..6778427d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import { initConfigContext } from "./cli/config-manager/config-context" -import type { Plugin } from "@opencode-ai/plugin" +import type { Hooks, Plugin, PluginModule } from "@opencode-ai/plugin" import type { HookName } from "./config" @@ -9,7 +9,6 @@ import { createRuntimeTmuxConfig, isTmuxIntegrationEnabled } from "./create-runt import { createTools } from "./create-tools" import { initializeOpenClaw } from "./openclaw" import { createPluginInterface } from "./plugin-interface" -import { createPluginDispose, type PluginDispose } from "./plugin-dispose" import { loadPluginConfig } from "./plugin-config" import { createModelCacheState } from "./plugin-state" @@ -17,27 +16,23 @@ import { createFirstMessageVariantGate } from "./shared/first-message-variant" import { injectServerAuthIntoClient, log, logLegacyPluginStartupWarning } from "./shared" import { detectExternalSkillPlugin, getSkillPluginConflictWarning } from "./shared/external-plugin-detector" import { startBackgroundCheck as startTmuxCheck } from "./tools/interactive-bash" -import { lspManager } from "./tools/lsp/client" import { createPluginPostHog, getPostHogDistinctId } from "./shared/posthog" -let activePluginDispose: PluginDispose | null = null - -const OhMyOpenCodePlugin: Plugin = async (ctx) => { +const serverPlugin: Plugin = async (input, _options): Promise => { initConfigContext("opencode", null) - log("[OhMyOpenCodePlugin] ENTRY - plugin loading", { - directory: ctx.directory, + log("[oh-my-openagent] ENTRY - plugin loading", { + directory: input.directory, }) logLegacyPluginStartupWarning() - const skillPluginCheck = detectExternalSkillPlugin(ctx.directory) + const skillPluginCheck = detectExternalSkillPlugin(input.directory) if (skillPluginCheck.detected && skillPluginCheck.pluginName) { console.warn(getSkillPluginConflictWarning(skillPluginCheck.pluginName)) } - injectServerAuthIntoClient(ctx.client) - await activePluginDispose?.() + injectServerAuthIntoClient(input.client) - const pluginConfig = loadPluginConfig(ctx.directory, ctx) + const pluginConfig = loadPluginConfig(input.directory, input) const posthog = createPluginPostHog() const distinctId = getPostHogDistinctId() @@ -78,7 +73,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { const modelCacheState = createModelCacheState() const managers = createManagers({ - ctx, + ctx: input, pluginConfig, tmuxConfig, modelCacheState, @@ -86,31 +81,25 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { }) const toolsResult = await createTools({ - ctx, + ctx: input, pluginConfig, managers, }) const hooks = createHooks({ - ctx, + ctx: input, pluginConfig, modelCacheState, backgroundManager: managers.backgroundManager, + modelFallbackControllerAccessor: managers.modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, mergedSkills: toolsResult.mergedSkills, availableSkills: toolsResult.availableSkills, }) - const dispose = createPluginDispose({ - backgroundManager: managers.backgroundManager, - skillMcpManager: managers.skillMcpManager, - lspManager, - disposeHooks: hooks.disposeHooks, - }) - const pluginInterface = createPluginInterface({ - ctx, + ctx: input, pluginConfig, firstMessageVariantGate, managers, @@ -118,30 +107,32 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => { tools: toolsResult.filteredTools, }) - activePluginDispose = dispose - return { - name: "oh-my-openagent", ...pluginInterface, "experimental.session.compacting": async ( - _input: { sessionID: string }, + compactingInput: { sessionID: string }, output: { context: string[] }, ): Promise => { - await hooks.compactionContextInjector?.capture(_input.sessionID) - await hooks.compactionTodoPreserver?.capture(_input.sessionID) + await hooks.compactionContextInjector?.capture(compactingInput.sessionID) + await hooks.compactionTodoPreserver?.capture(compactingInput.sessionID) await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( - _input, + compactingInput, output, ) if (hooks.compactionContextInjector) { - output.context.push(hooks.compactionContextInjector.inject(_input.sessionID)) + output.context.push(hooks.compactionContextInjector.inject(compactingInput.sessionID)) } }, } } -export default OhMyOpenCodePlugin +const pluginModule: PluginModule = { + id: "oh-my-openagent", + server: serverPlugin, +} + +export default pluginModule export type { OhMyOpenCodeConfig, diff --git a/src/mcp/AGENTS.md b/src/mcp/AGENTS.md index 2518ba92f..4914d491b 100644 --- a/src/mcp/AGENTS.md +++ b/src/mcp/AGENTS.md @@ -1,6 +1,6 @@ # src/mcp/ — 3 Built-in Remote MCPs -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/openclaw/AGENTS.md b/src/openclaw/AGENTS.md index 93b32eff3..680141de8 100644 --- a/src/openclaw/AGENTS.md +++ b/src/openclaw/AGENTS.md @@ -1,6 +1,6 @@ # src/openclaw/ — Bidirectional External Integration -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/plugin-dispose.test.ts b/src/plugin-dispose.test.ts deleted file mode 100644 index d0dd0285b..000000000 --- a/src/plugin-dispose.test.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { describe, expect, spyOn, test } from "bun:test" - -import { disposeCreatedHooks } from "./create-hooks" -import { createPluginDispose } from "./plugin-dispose" - -describe("createPluginDispose", () => { - test("#given plugin with active managers and hooks #when dispose() is called #then backgroundManager.shutdown() is called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - }) - - test("#given plugin with active MCP connections #when dispose() is called #then skillMcpManager.disconnectAll() is called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - }) - - test("#given plugin with hooks that have dispose #when dispose() is called #then each hook's dispose is called", async () => { - // given - const claudeCodeHooks = { - dispose: (): void => {}, - } - const commentChecker = { - dispose: (): void => {}, - } - const runtimeFallback = { - dispose: (): void => {}, - } - const todoContinuationEnforcer = { - dispose: (): void => {}, - } - const autoSlashCommand = { - dispose: (): void => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const claudeCodeHooksDisposeSpy = spyOn(claudeCodeHooks, "dispose") - const commentCheckerDisposeSpy = spyOn(commentChecker, "dispose") - const runtimeFallbackDisposeSpy = spyOn(runtimeFallback, "dispose") - const todoContinuationEnforcerDisposeSpy = spyOn(todoContinuationEnforcer, "dispose") - const autoSlashCommandDisposeSpy = spyOn(autoSlashCommand, "dispose") - const dispose = createPluginDispose({ - backgroundManager: { - shutdown: async (): Promise => {}, - }, - skillMcpManager: { - disconnectAll: async (): Promise => {}, - }, - lspManager, - disposeHooks: (): void => { - disposeCreatedHooks({ - claudeCodeHooks, - commentChecker, - runtimeFallback, - todoContinuationEnforcer, - autoSlashCommand, - }) - }, - }) - - // when - await dispose() - - // then - expect(claudeCodeHooksDisposeSpy).toHaveBeenCalledTimes(1) - expect(commentCheckerDisposeSpy).toHaveBeenCalledTimes(1) - expect(runtimeFallbackDisposeSpy).toHaveBeenCalledTimes(1) - expect(todoContinuationEnforcerDisposeSpy).toHaveBeenCalledTimes(1) - expect(autoSlashCommandDisposeSpy).toHaveBeenCalledTimes(1) - }) - - test("#given dispose already called #when dispose() called again #then no errors", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooks = { - run: (): void => {}, - } - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const stopAllSpy = spyOn(lspManager, "stopAll") - const disposeHooksSpy = spyOn(disposeHooks, "run") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: disposeHooks.run, - }) - - // when - await dispose() - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - expect(stopAllSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksSpy).toHaveBeenCalledTimes(1) - }) - - test("#given backgroundManager.shutdown() throws #when dispose() is called #then skillMcpManager.disconnectAll() and disposeHooks() are still called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => { - throw new Error("shutdown failed") - }, - } - const skillMcpManager = { - disconnectAll: async (): Promise => {}, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooksCalls: number[] = [] - const disconnectAllSpy = spyOn(skillMcpManager, "disconnectAll") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => { - disposeHooksCalls.push(1) - }, - }) - - // when - await dispose() - - // then - expect(disconnectAllSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksCalls).toHaveLength(1) - }) - - test("#given skillMcpManager.disconnectAll() throws #when dispose() is called #then disposeHooks() is still called", async () => { - // given - const backgroundManager = { - shutdown: async (): Promise => {}, - } - const skillMcpManager = { - disconnectAll: async (): Promise => { - throw new Error("disconnectAll failed") - }, - } - const lspManager = { - stopAll: async (): Promise => {}, - } - const disposeHooksCalls: number[] = [] - const shutdownSpy = spyOn(backgroundManager, "shutdown") - const dispose = createPluginDispose({ - backgroundManager, - skillMcpManager, - lspManager, - disposeHooks: (): void => { - disposeHooksCalls.push(1) - }, - }) - - // when - await dispose() - - // then - expect(shutdownSpy).toHaveBeenCalledTimes(1) - expect(disposeHooksCalls).toHaveLength(1) - }) - - test("#given active LSP clients #when dispose runs #then lsp manager is stopped", async () => { - // given - const lspManager = { - stopAll: async (): Promise => {}, - } - const stopAllSpy = spyOn(lspManager, "stopAll") - const dispose = createPluginDispose({ - backgroundManager: { - shutdown: async (): Promise => {}, - }, - skillMcpManager: { - disconnectAll: async (): Promise => {}, - }, - lspManager, - disposeHooks: (): void => {}, - }) - - // when - await dispose() - - // then - expect(stopAllSpy).toHaveBeenCalledTimes(1) - }) -}) diff --git a/src/plugin-dispose.ts b/src/plugin-dispose.ts deleted file mode 100644 index 998fd28eb..000000000 --- a/src/plugin-dispose.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { log } from "./shared" - -export type PluginDispose = () => Promise - -export function createPluginDispose(args: { - backgroundManager: { - shutdown: () => void | Promise - } - skillMcpManager: { - disconnectAll: () => Promise - } - lspManager: { - stopAll: () => Promise - } - disposeHooks: () => void -}): PluginDispose { - const { backgroundManager, skillMcpManager, lspManager, disposeHooks } = args - let disposePromise: Promise | null = null - - return async (): Promise => { - if (disposePromise) { - await disposePromise - return - } - - disposePromise = (async (): Promise => { - try { - await backgroundManager.shutdown() - } catch (error) { - log("[plugin-dispose] backgroundManager.shutdown() error:", error) - } - try { - await skillMcpManager.disconnectAll() - } catch (error) { - log("[plugin-dispose] skillMcpManager.disconnectAll() error:", error) - } - try { - await lspManager.stopAll() - } catch (error) { - log("[plugin-dispose] lspManager.stopAll() error:", error) - } - try { - disposeHooks() - } catch (error) { - log("[plugin-dispose] disposeHooks() error:", error) - } - })() - - await disposePromise - } -} diff --git a/src/plugin-handlers/AGENTS.md b/src/plugin-handlers/AGENTS.md index f0d9949a7..df6c8bf14 100644 --- a/src/plugin-handlers/AGENTS.md +++ b/src/plugin-handlers/AGENTS.md @@ -1,6 +1,6 @@ # src/plugin-handlers/ — 6-Phase Config Loading Pipeline -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## CRITICAL: AGENT ORDERING diff --git a/src/plugin-handlers/agent-config-handler-agents-skills.test.ts b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts index 593f22d9e..4bb94ce41 100644 --- a/src/plugin-handlers/agent-config-handler-agents-skills.test.ts +++ b/src/plugin-handlers/agent-config-handler-agents-skills.test.ts @@ -81,7 +81,7 @@ describe("applyAgentConfig .agents skills", () => { // when await applyAgentConfig({ - config: { model: "anthropic/claude-opus-4-6", agent: {} }, + config: { model: "anthropic/claude-opus-4-7", agent: {} }, pluginConfig: createPluginConfig(), ctx: { directory }, pluginComponents: createPluginComponents(), @@ -111,7 +111,7 @@ describe("applyAgentConfig .agents skills", () => { // when await applyAgentConfig({ - config: { model: "anthropic/claude-opus-4-6", agent: {} }, + config: { model: "anthropic/claude-opus-4-7", agent: {} }, pluginConfig: createPluginConfig(), ctx: { directory: "/tmp/project" }, pluginComponents: createPluginComponents(), diff --git a/src/plugin-handlers/agent-config-handler.test.ts b/src/plugin-handlers/agent-config-handler.test.ts index 8e2571e34..afca8f62b 100644 --- a/src/plugin-handlers/agent-config-handler.test.ts +++ b/src/plugin-handlers/agent-config-handler.test.ts @@ -31,7 +31,7 @@ function createPluginComponents(): PluginComponents { function createBaseConfig(): Record { return { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } } diff --git a/src/plugin-handlers/config-handler.test.ts b/src/plugin-handlers/config-handler.test.ts index 668d21a32..629f97796 100644 --- a/src/plugin-handlers/config-handler.test.ts +++ b/src/plugin-handlers/config-handler.test.ts @@ -88,7 +88,7 @@ beforeEach(async () => { spyOn(mcpModule, "createBuiltinMcps" as any).mockReturnValue({}) spyOn(shared, "log" as any).mockImplementation(() => {}) - spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set(["anthropic/claude-opus-4-6"])) + spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set(["anthropic/claude-opus-4-7"])) spyOn(shared, "readConnectedProvidersCache" as any).mockReturnValue(null) spyOn(configDir, "getOpenCodeConfigPaths" as any).mockReturnValue({ @@ -98,7 +98,7 @@ beforeEach(async () => { spyOn(permissionCompat, "migrateAgentConfig" as any).mockImplementation((config: Record) => config) - spyOn(modelResolver, "resolveModelWithFallback" as any).mockReturnValue({ model: "anthropic/claude-opus-4-6" }) + spyOn(modelResolver, "resolveModelWithFallback" as any).mockReturnValue({ model: "anthropic/claude-opus-4-7" }) ;({ createConfigHandler } = await importFreshConfigHandlerModule()) }) @@ -204,7 +204,7 @@ describe("MCP env allowlist initialization", () => { mcp_env_allowlist: ["CUSTOM_API_KEY", "CUSTOM_AUTH_TOKEN"], }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -246,7 +246,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -292,7 +292,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -336,7 +336,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -385,7 +385,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -422,7 +422,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -459,7 +459,7 @@ describe("Plan agent demote behavior", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -495,7 +495,7 @@ describe("Agent permission defaults", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -523,7 +523,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " hephaestus ", agent: {}, } @@ -547,7 +547,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "HePhAeStUs", agent: {}, } @@ -571,7 +571,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // #given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "hephaestus", agent: {}, } @@ -596,7 +596,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { const pluginConfig = createPluginConfig({}) const displayName = getAgentListDisplayName("hephaestus") const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: displayName, agent: {}, } @@ -620,7 +620,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // #given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -643,7 +643,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: "hephaestus", agent: {}, } @@ -667,7 +667,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " ", agent: {}, } @@ -691,7 +691,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { // given const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " Custom Agent ", agent: {}, } @@ -719,7 +719,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", default_agent: " HePhAeStUs ", agent: {}, } @@ -861,7 +861,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -902,7 +902,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -944,7 +944,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -980,7 +980,7 @@ describe("Prometheus direct override priority over category", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1007,9 +1007,9 @@ describe("Prometheus direct override priority over category", () => { describe("Plan agent model inheritance from prometheus", () => { test("plan agent inherits all model-related settings from resolved prometheus config", async () => { - //#given - prometheus resolves to claude-opus-4-6 with model settings + //#given - prometheus resolves to claude-opus-4-7 with model settings spyOn(prometheusAgentConfigBuilder, "buildPrometheusAgentConfig").mockResolvedValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", mode: "primary", prompt: "prometheus prompt", @@ -1021,7 +1021,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: { plan: { name: "plan", @@ -1047,7 +1047,7 @@ describe("Plan agent model inheritance from prometheus", () => { const agents = config.agent as Record expect(agents.plan).toBeDefined() expect(agents.plan.mode).toBe("subagent") - expect(agents.plan.model).toBe("anthropic/claude-opus-4-6") + expect(agents.plan.model).toBe("anthropic/claude-opus-4-7") expect(agents.plan.variant).toBe("max") expect(agents.plan.prompt).toBeUndefined() }) @@ -1078,7 +1078,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1110,7 +1110,7 @@ describe("Plan agent model inheritance from prometheus", () => { test("plan agent user override takes priority over prometheus inherited settings", async () => { //#given - prometheus resolves to opus, but user has plan override for gpt-5.4 spyOn(shared, "resolveModelPipeline" as any).mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", variant: "max", }) @@ -1128,7 +1128,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1153,7 +1153,7 @@ describe("Plan agent model inheritance from prometheus", () => { test("plan agent does NOT inherit prompt, description, or color from prometheus", async () => { //#given spyOn(shared, "resolveModelPipeline" as any).mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", variant: "max", }) @@ -1164,7 +1164,7 @@ describe("Plan agent model inheritance from prometheus", () => { }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1181,7 +1181,7 @@ describe("Plan agent model inheritance from prometheus", () => { //#then - plan has model settings but NOT prompt/description/color const agents = config.agent as Record> - expect(agents.plan.model).toBe("anthropic/claude-opus-4-6") + expect(agents.plan.model).toBe("anthropic/claude-opus-4-7") expect(agents.plan.prompt).toBeUndefined() expect(agents.plan.description).toBeUndefined() expect(agents.plan.color).toBeUndefined() @@ -1200,7 +1200,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", ( }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const mockClient = { @@ -1233,7 +1233,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash")) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1263,7 +1263,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { experimental: { plugin_load_timeout_ms: 100 }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1289,7 +1289,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { spyOn(pluginLoader, "loadAllPluginComponents" as any).mockRejectedValue(new Error("crash")) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1326,7 +1326,7 @@ describe("config-handler plugin loading error boundary (#1559)", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const { createConfigHandler: createFreshConfigHandler } = await importFreshConfigHandlerModule() @@ -1370,7 +1370,7 @@ describe("command agent routing coherence", () => { }) const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1420,7 +1420,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { experimental: { task_system: true }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1458,7 +1458,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { experimental: { task_system: false }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1497,7 +1497,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1538,7 +1538,7 @@ describe("disable_omo_env pass-through", () => { experimental: { disable_omo_env: true }, }) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1575,7 +1575,7 @@ describe("disable_omo_env pass-through", () => { const pluginConfig = createPluginConfig({}) const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1621,7 +1621,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1661,7 +1661,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1701,7 +1701,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ @@ -1749,7 +1749,7 @@ describe("Agent merge priority — project-local overrides global", () => { const pluginConfig: OhMyOpenCodeConfig = {} const config: Record = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", agent: {}, } const handler = createConfigHandler({ diff --git a/src/plugin-handlers/plan-model-inheritance.test.ts b/src/plugin-handlers/plan-model-inheritance.test.ts index c36948856..5df73a9f8 100644 --- a/src/plugin-handlers/plan-model-inheritance.test.ts +++ b/src/plugin-handlers/plan-model-inheritance.test.ts @@ -18,7 +18,7 @@ describe("buildPlanDemoteConfig", () => { //#given const prometheusConfig = { name: "prometheus", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", mode: "primary", prompt: "You are Prometheus...", @@ -39,7 +39,7 @@ describe("buildPlanDemoteConfig", () => { //#then - picks model settings, NOT prompt/permission/description/color/name/mode expect(result.mode).toBe("subagent") - expect(result.model).toBe("anthropic/claude-opus-4-6") + expect(result.model).toBe("anthropic/claude-opus-4-7") expect(result.variant).toBe("max") expect(result.temperature).toBe(0.1) expect(result.top_p).toBe(0.95) @@ -58,7 +58,7 @@ describe("buildPlanDemoteConfig", () => { test("plan override takes priority over prometheus for all model settings", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", temperature: 0.1, reasoningEffort: "high", @@ -83,7 +83,7 @@ describe("buildPlanDemoteConfig", () => { test("falls back to prometheus when plan override has partial settings", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", temperature: 0.1, reasoningEffort: "high", @@ -105,14 +105,14 @@ describe("buildPlanDemoteConfig", () => { test("skips undefined values from both sources", () => { //#given const prometheusConfig = { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", } //#when const result = buildPlanDemoteConfig(prometheusConfig, undefined) //#then - expect(result).toEqual({ mode: "subagent", hidden: true, model: "anthropic/claude-opus-4-6" }) + expect(result).toEqual({ mode: "subagent", hidden: true, model: "anthropic/claude-opus-4-7" }) expect(Object.keys(result)).toEqual(["mode", "hidden", "model"]) }) }) diff --git a/src/plugin-handlers/prometheus-agent-config-builder.test.ts b/src/plugin-handlers/prometheus-agent-config-builder.test.ts index be19047f4..8c77f562d 100644 --- a/src/plugin-handlers/prometheus-agent-config-builder.test.ts +++ b/src/plugin-handlers/prometheus-agent-config-builder.test.ts @@ -24,7 +24,7 @@ describe("buildPrometheusAgentConfig", () => { (category) => ({ model: `${category}/default-model` } as CategoryConfig) ); resolveModelPipelineSpy = spyOn(shared, "resolveModelPipeline").mockReturnValue({ - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", provenance: "provider-fallback", }); ;({ buildPrometheusAgentConfig } = await importFreshPrometheusAgentConfigBuilderModule()) @@ -42,7 +42,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#when currentModel is NOT in Prometheus fallback chain", () => { test("falls through to fallback chain instead of using currentModel as override", async () => { // given - currentModel is a model NOT in Prometheus fallback chain - // Prometheus chain: claude-opus-4-6, gpt-5.4, glm-5, gemini-3.1-pro + // Prometheus chain: claude-opus-4-7, gpt-5.4, glm-5, gemini-3.1-pro const currentModel = "some-provider/gpt-5.3-codex"; // when @@ -65,14 +65,14 @@ describe("buildPrometheusAgentConfig", () => { systemDefaultModel: undefined, }), }); - expect(result.model).toBe("anthropic/claude-opus-4-6"); + expect(result.model).toBe("anthropic/claude-opus-4-7"); }); }); describe("#when currentModel IS in Prometheus fallback chain", () => { - test("preserves currentModel as uiSelectedModel for claude-opus-4-6", async () => { + test("preserves currentModel as uiSelectedModel for claude-opus-4-7", async () => { // given - currentModel matches a Prometheus fallback chain entry - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; // when - should not throw and should produce a valid config const result = await buildPrometheusAgentConfig({ @@ -128,7 +128,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#given explicit Prometheus model configured via plugin override", () => { test("explicit config wins over currentModel and fallback chain", async () => { // given - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; const explicitModel = "custom-provider/custom-model"; // when @@ -163,7 +163,7 @@ describe("buildPrometheusAgentConfig", () => { describe("#given category with model configured", () => { test("category model wins when no explicit override", async () => { // given - const currentModel = "anthropic/claude-opus-4-6"; + const currentModel = "anthropic/claude-opus-4-7"; const categoryModel = "category-provider/category-model"; resolveCategoryConfigSpy.mockReturnValue({ @@ -264,7 +264,7 @@ describe("buildPrometheusAgentConfig", () => { }, }) ); - expect(result.model).toBe("anthropic/claude-opus-4-6"); + expect(result.model).toBe("anthropic/claude-opus-4-7"); }); }); diff --git a/src/plugin/AGENTS.md b/src/plugin/AGENTS.md index c58d32000..94732c5b9 100644 --- a/src/plugin/AGENTS.md +++ b/src/plugin/AGENTS.md @@ -1,6 +1,6 @@ # src/plugin/ — 10 OpenCode Hook Handlers + Hook Composition -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/plugin/chat-message.test.ts b/src/plugin/chat-message.test.ts index 6ecac08bb..e2e813cd8 100644 --- a/src/plugin/chat-message.test.ts +++ b/src/plugin/chat-message.test.ts @@ -709,7 +709,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { shouldOverride: false, pluginConfig: { agents: { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, }, }, }) @@ -733,7 +733,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { shouldOverride: false, pluginConfig: { agents: { - prometheus: { model: "anthropic/claude-opus-4-6" }, + prometheus: { model: "anthropic/claude-opus-4-7" }, }, }, }) @@ -753,7 +753,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { test("respects a mid-conversation model switch instead of reusing the previous stored model", async () => { //#given setMainSession("test-session") - setSessionModel("test-session", { providerID: "anthropic", modelID: "claude-opus-4-6" }) + setSessionModel("test-session", { providerID: "anthropic", modelID: "claude-opus-4-7" }) const args = createMockHandlerArgs({ shouldOverride: false }) const handler = createChatMessageHandler(args) const nextModel = { providerID: "openai", modelID: "gpt-5.4" } diff --git a/src/plugin/chat-params.test.ts b/src/plugin/chat-params.test.ts index f75c1a243..5886b7204 100644 --- a/src/plugin/chat-params.test.ts +++ b/src/plugin/chat-params.test.ts @@ -48,7 +48,7 @@ describe("createChatParamsHandler", () => { const input = { sessionID: "ses_chat_params", agent: { name: "sisyphus" }, - model: { providerID: "opencode", modelID: "claude-opus-4-6" }, + model: { providerID: "opencode", modelID: "claude-opus-4-7" }, provider: { id: "opencode" }, message: {}, } diff --git a/src/plugin/event-compaction-agent.test.ts b/src/plugin/event-compaction-agent.test.ts index b247b649e..b5888d7fe 100644 --- a/src/plugin/event-compaction-agent.test.ts +++ b/src/plugin/event-compaction-agent.test.ts @@ -73,7 +73,7 @@ describe("createEventHandler compaction agent filtering", () => { role: "user", agent: "compaction", time: { created: Date.now() }, - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, }, }, }, diff --git a/src/plugin/event.model-fallback-2941.test.ts b/src/plugin/event.model-fallback-2941.test.ts index 46765a5d9..2b97d2cb7 100644 --- a/src/plugin/event.model-fallback-2941.test.ts +++ b/src/plugin/event.model-fallback-2941.test.ts @@ -65,13 +65,13 @@ function createChatMessageHandlerHooks(modelFallback: ReturnType void } | undefined let readProviderModelsCacheSpy: { mockRestore: () => void } | undefined -afterEach(() => { - readConnectedProvidersCacheSpy?.mockRestore() - readProviderModelsCacheSpy?.mockRestore() - readConnectedProvidersCacheSpy = undefined - readProviderModelsCacheSpy = undefined - _resetForTesting() -}) + afterEach(() => { + readConnectedProvidersCacheSpy?.mockRestore() + readProviderModelsCacheSpy?.mockRestore() + readConnectedProvidersCacheSpy = undefined + readProviderModelsCacheSpy = undefined + _resetForTesting() + }) describe("createEventHandler - category runtime fallback suppression", () => { test("does not arm retry fallback when category session explicitly stores no fallback chain [regression #2941]", async () => { @@ -83,11 +83,10 @@ describe("createEventHandler - category runtime fallback suppression", () => { readConnectedProvidersCacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) readProviderModelsCacheSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue(null) - clearPendingModelFallback(sessionID) - setSessionAgent(sessionID, "sisyphus-junior") - setSessionFallbackChain(sessionID, undefined) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) + setSessionAgent(sessionID, "sisyphus-junior") + setSessionFallbackChain(modelFallback, sessionID, undefined) const eventHandler = createEventHandler({ ctx: asEventHandlerContext({ directory: "/tmp", diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 481c5c419..967608f09 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -85,12 +85,12 @@ describe("createEventHandler - model fallback", () => { name: "APIError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", isRetryable: true, }, }, parentID: "msg_user_1", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", mode: "Sisyphus - Ultraworker", agent: "Sisyphus - Ultraworker", @@ -125,7 +125,7 @@ describe("createEventHandler - model fallback", () => { data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, @@ -142,9 +142,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_fallback" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const { handler, abortCalls, promptCalls } = createHandler({ hooks: { modelFallback } }) @@ -182,7 +181,7 @@ describe("createEventHandler - model fallback", () => { role: "user", time: { created: 1 }, content: [], - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -201,7 +200,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", next: 1234, }, }, @@ -213,7 +212,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, output, ) @@ -232,8 +231,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_dedup" setMainSession(sessionID) - clearPendingModelFallback(sessionID) const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const { handler, abortCalls, promptCalls } = createHandler({ hooks: { modelFallback } }) await handler({ @@ -244,7 +243,7 @@ describe("createEventHandler - model fallback", () => { id: "msg_user_status_dedup", sessionID, role: "user", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", }, @@ -262,7 +261,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", next: 300, }, }, @@ -277,7 +276,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~4 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~4 days attempt #1]", next: 299, }, }, @@ -293,8 +292,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_runtime_enabled" setMainSession(sessionID) - clearPendingModelFallback(sessionID) const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const runtimeFallback = { event: async () => {}, "chat.message": async () => {}, @@ -312,7 +311,7 @@ describe("createEventHandler - model fallback", () => { id: "msg_user_status_runtime_enabled", sessionID, role: "user", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", providerID: "quotio", agent: "Sisyphus - Ultraworker", }, @@ -330,7 +329,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", next: 476, }, }, @@ -346,9 +345,8 @@ describe("createEventHandler - model fallback", () => { //#given const sessionID = "ses_status_retry_user_fallback" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const pluginConfig = { agents: { sisyphus: { @@ -393,7 +391,7 @@ describe("createEventHandler - model fallback", () => { role: "user", time: { created: 1 }, content: [], - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", providerID: "quotio", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -412,7 +410,7 @@ describe("createEventHandler - model fallback", () => { type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", next: 300, }, }, @@ -424,7 +422,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "quotio", modelID: "claude-opus-4-6" }, + model: { providerID: "quotio", modelID: "claude-opus-4-7" }, }, output, ) @@ -446,9 +444,8 @@ describe("createEventHandler - model fallback", () => { const toastCalls: string[] = [] const sessionID = "ses_main_fallback_chain" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) setupConnectedProviderCacheMocks() const eventHandler = createEventHandler({ @@ -520,13 +517,13 @@ describe("createEventHandler - model fallback", () => { properties: { sessionID, providerID: "anthropic", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", error: { name: "UnknownError", data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, @@ -539,7 +536,7 @@ describe("createEventHandler - model fallback", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, output, ) @@ -549,7 +546,7 @@ describe("createEventHandler - model fallback", () => { //#when - first retry cycle const first = await triggerRetryCycle() - //#then - first fallback entry applied (no-op skip: claude-opus-4-6 matches current model after normalization) + //#then - first fallback entry applied (no-op skip: claude-opus-4-7 matches current model after normalization) expect(first.message["model"]).toMatchObject({ providerID: "opencode-go", modelID: "kimi-k2.5", @@ -590,12 +587,12 @@ describe("createEventHandler - model fallback", () => { name: "APIError", data: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", isRetryable: true, }, }, parentID: "msg_user_disabled_1", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, @@ -617,7 +614,7 @@ describe("createEventHandler - model fallback", () => { data: { error: { message: - "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-6-thinking\"}}", + "Bad Gateway: {\"error\":{\"message\":\"unknown provider for model claude-opus-4-7-thinking\"}}", }, }, }, diff --git a/src/plugin/event.test.ts b/src/plugin/event.test.ts index 85223806c..ea880c145 100644 --- a/src/plugin/event.test.ts +++ b/src/plugin/event.test.ts @@ -761,11 +761,10 @@ describe("createEventHandler - retry dedupe lifecycle", () => { //#given const sessionID = "ses_retry_recovery_rearm" setMainSession(sessionID) - clearPendingModelFallback(sessionID) - const abortCalls: string[] = [] const promptCalls: string[] = [] const modelFallback = createModelFallbackHook() + clearPendingModelFallback(modelFallback, sessionID) const eventHandler = createEventHandler({ ctx: asEventHandlerContext({ @@ -826,7 +825,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { const retryStatus = { type: "retry", attempt: 1, - message: "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in 7m 56s attempt #1]", + message: "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in 7m 56s attempt #1]", next: 476, } as const @@ -838,7 +837,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { id: "msg_user_retry_rearm", sessionID, role: "user", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", providerID: "anthropic", agent: "Sisyphus - Ultraworker", }, @@ -862,7 +861,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { { sessionID, agent: "sisyphus", - model: { providerID: "anthropic", modelID: "claude-opus-4-6-thinking" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7-thinking" }, }, firstOutput, ) diff --git a/src/plugin/event.ts b/src/plugin/event.ts index 34bc730e1..5a5f177b6 100644 --- a/src/plugin/event.ts +++ b/src/plugin/event.ts @@ -15,6 +15,7 @@ import { clearSessionFallbackChain, setSessionFallbackChain, setPendingModelFallback, + type ModelFallbackHook, } from "../hooks/model-fallback/hook"; import { getRawFallbackModels } from "../hooks/runtime-fallback/fallback-models"; import { @@ -111,6 +112,7 @@ function extractProviderModelFromErrorMessage(message: string): { providerID?: s return {}; } function applyUserConfiguredFallbackChain( + modelFallback: Pick | null | undefined, sessionID: string, agentName: string, currentProviderID: string, @@ -123,7 +125,9 @@ function applyUserConfiguredFallbackChain( const fallbackChain = buildFallbackChainFromModels(rawFallbackModels, currentProviderID); if (fallbackChain && fallbackChain.length > 0) { - setSessionFallbackChain(sessionID, fallbackChain); + if (modelFallback) { + setSessionFallbackChain(modelFallback, sessionID, fallbackChain); + } } } @@ -170,6 +174,7 @@ export function createEventHandler(args: { const isModelFallbackEnabled = hooks.modelFallback !== null && hooks.modelFallback !== undefined; + const modelFallback = hooks.modelFallback; // Avoid triggering multiple abort+continue cycles for the same failing assistant message. const lastHandledModelErrorMessageID = new Map(); @@ -408,8 +413,10 @@ export function createEventHandler(args: { lastHandledModelErrorMessageID.delete(sessionInfo.id); lastHandledRetryStatusKey.delete(sessionInfo.id); lastKnownModelBySession.delete(sessionInfo.id); - clearPendingModelFallback(sessionInfo.id); - clearSessionFallbackChain(sessionInfo.id); + if (modelFallback) { + clearPendingModelFallback(modelFallback, sessionInfo.id); + clearSessionFallbackChain(modelFallback, sessionInfo.id); + } resetMessageCursor(sessionInfo.id); clearBackgroundOutputConsumptionsForParentSession(sessionInfo.id); clearBackgroundOutputConsumptionsForTaskSession(sessionInfo.id); @@ -515,11 +522,13 @@ export function createEventHandler(args: { sessionID, info?.providerID as string | undefined, ); - const rawModel = (info?.modelID as string | undefined) ?? "claude-opus-4-6"; + const rawModel = (info?.modelID as string | undefined) ?? "claude-opus-4-7"; const currentModel = normalizeFallbackModelID(rawModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && @@ -578,11 +587,13 @@ export function createEventHandler(args: { const parsed = extractProviderModelFromErrorMessage(retryMessage); const lastKnown = lastKnownModelBySession.get(sessionID); const currentProvider = resolveFallbackProviderID(sessionID, parsed.providerID); - let currentModel = parsed.modelID ?? lastKnown?.modelID ?? "claude-opus-4-6"; + let currentModel = parsed.modelID ?? lastKnown?.modelID ?? "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && @@ -664,11 +675,13 @@ export function createEventHandler(args: { sessionID, (props?.providerID as string | undefined) || parsed.providerID, ); - let currentModel = (props?.modelID as string) || parsed.modelID || "claude-opus-4-6"; + let currentModel = (props?.modelID as string) || parsed.modelID || "claude-opus-4-7"; currentModel = normalizeFallbackModelID(currentModel); - applyUserConfiguredFallbackChain(sessionID, agentName, currentProvider, args.pluginConfig); + applyUserConfiguredFallbackChain(modelFallback, sessionID, agentName, currentProvider, args.pluginConfig); - const setFallback = setPendingModelFallback(sessionID, agentName, currentProvider, currentModel); + const setFallback = modelFallback + ? setPendingModelFallback(modelFallback, sessionID, agentName, currentProvider, currentModel) + : false; if ( setFallback && diff --git a/src/plugin/fallback.cliproxyapi-matrix.test.ts b/src/plugin/fallback.cliproxyapi-matrix.test.ts index 30535a880..3d1b5fd4c 100644 --- a/src/plugin/fallback.cliproxyapi-matrix.test.ts +++ b/src/plugin/fallback.cliproxyapi-matrix.test.ts @@ -9,7 +9,6 @@ import { createModelFallbackHook } from "../hooks/model-fallback/hook" import { createRuntimeFallbackHook } from "../hooks/runtime-fallback" import type { RuntimeFallbackPluginInput } from "../hooks/runtime-fallback/types" import { _resetForTesting } from "../features/claude-code-session-state" -import { _resetForTesting as _resetModelFallbackForTesting } from "../hooks/model-fallback/hook" import { SessionCategoryRegistry } from "../shared/session-category-registry" import * as connectedProvidersCache from "../shared/connected-providers-cache" @@ -59,7 +58,7 @@ function createChatMessageHandlerHooks( const PRIMARY_MODEL = { providerID: PROVIDER_ID, - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", } const PRIMARY_MODEL_STRING = `${PRIMARY_MODEL.providerID}/${PRIMARY_MODEL.modelID}` @@ -313,7 +312,7 @@ async function triggerSessionStatusRetry( type: "retry", attempt: 1, message: - "All credentials for model claude-opus-4-6 are cooling down [retrying in 7m 56s attempt #1]", + "All credentials for model claude-opus-4-7 are cooling down [retrying in 7m 56s attempt #1]", next: 476, }, }, @@ -369,7 +368,6 @@ function setupConnectedProviderCacheMocks(): void { afterEach(() => { _resetForTesting() - _resetModelFallbackForTesting() SessionCategoryRegistry.clear() }) diff --git a/src/plugin/hooks/create-core-hooks.ts b/src/plugin/hooks/create-core-hooks.ts index 4da2b5085..5a36aa026 100644 --- a/src/plugin/hooks/create-core-hooks.ts +++ b/src/plugin/hooks/create-core-hooks.ts @@ -1,4 +1,5 @@ import type { HookName, OhMyOpenCodeConfig } from "../../config" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { PluginContext } from "../types" import type { ModelCacheState } from "../../plugin-state" @@ -10,15 +11,17 @@ export function createCoreHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean }) { - const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args + const { ctx, pluginConfig, modelCacheState, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args const session = createSessionHooks({ ctx, pluginConfig, modelCacheState, + modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled, }) diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index af87bd366..9d437bc75 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -1,4 +1,5 @@ import type { OhMyOpenCodeConfig, HookName } from "../../config" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { ModelCacheState } from "../../plugin-state" import type { PluginContext } from "../types" @@ -69,10 +70,11 @@ export function createSessionHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean }): SessionHooks { - const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args + const { ctx, pluginConfig, modelCacheState, modelFallbackControllerAccessor, isHookEnabled, safeHookEnabled } = args const safeHook = (hookName: HookName, factory: () => T): T | null => safeCreateHook(hookName, factory, { enabled: safeHookEnabled }) @@ -171,6 +173,7 @@ export function createSessionHooks(args: { .catch(() => {}) }, onApplied: enableFallbackTitle ? updateFallbackTitle : undefined, + controllerAccessor: modelFallbackControllerAccessor, })) : null diff --git a/src/plugin/tool-execute-after.test.ts b/src/plugin/tool-execute-after.test.ts index cb70a91f8..7c8e9d87c 100644 --- a/src/plugin/tool-execute-after.test.ts +++ b/src/plugin/tool-execute-after.test.ts @@ -1,7 +1,13 @@ -import { describe, expect, it } from "bun:test" +import { beforeEach, describe, expect, it } from "bun:test" + +import { clearPendingStore, storeToolMetadata } from "../features/tool-metadata-store" import { createToolExecuteAfterHandler } from "./tool-execute-after" describe("createToolExecuteAfterHandler", () => { + beforeEach(() => { + clearPendingStore() + }) + it("#given truncator changes output #when tool.execute.after runs #then claudeCodeHooks receives truncated output", async () => { const callOrder: string[] = [] let claudeSawOutput = "" @@ -32,4 +38,58 @@ describe("createToolExecuteAfterHandler", () => { expect(callOrder).toEqual(["truncator", "claude"]) expect(claudeSawOutput).toBe("truncated output") }) + + it("#given stored metadata with legacy call id casing #when tool.execute.after runs #then it restores the stored metadata", async () => { + // given + storeToolMetadata("ses_parent", "call_legacy", { + title: "stored title", + metadata: { sessionId: "ses_child", agent: "oracle" }, + }) + + const handler = createToolExecuteAfterHandler({ + ctx: { directory: "/repo" } as never, + hooks: {} as never, + }) + + const output = { title: "result", output: "original output", metadata: { truncated: true } } + + // when + await handler( + { tool: "hashline_edit", sessionID: "ses_parent", callId: " call_legacy " }, + output + ) + + // then + expect(output.title).toBe("stored title") + expect(output.metadata).toEqual({ truncated: true, sessionId: "ses_child", agent: "oracle" }) + }) + + it("#given native session metadata #when stored metadata exists #then stored metadata does not overwrite native session linkage", async () => { + // given + storeToolMetadata("ses_parent", "call_native", { + title: "stored title", + metadata: { sessionId: "ses_stored", agent: "oracle" }, + }) + + const handler = createToolExecuteAfterHandler({ + ctx: { directory: "/repo" } as never, + hooks: {} as never, + }) + + const output = { + title: "result", + output: "original output", + metadata: { sessionId: "ses_native", agent: "hephaestus" }, + } + + // when + await handler( + { tool: "hashline_edit", sessionID: "ses_parent", callID: "call_native" }, + output + ) + + // then + expect(output.title).toBe("stored title") + expect(output.metadata).toEqual({ sessionId: "ses_native", agent: "hephaestus" }) + }) }) diff --git a/src/plugin/tool-execute-after.ts b/src/plugin/tool-execute-after.ts index b0c31bb47..19bb724d7 100644 --- a/src/plugin/tool-execute-after.ts +++ b/src/plugin/tool-execute-after.ts @@ -1,9 +1,8 @@ -import { consumeToolMetadata } from "../features/tool-metadata-store" +import { recoverToolMetadata } from "../features/tool-metadata-store" import type { CreatedHooks } from "../create-hooks" -import { log } from "../shared" +import { log } from "../shared/logger" import { stripInvisibleAgentCharacters } from "../shared/agent-display-names" import type { PluginContext } from "./types" -import { readState, writeState } from "../hooks/ralph-loop/storage" const VERIFICATION_ATTEMPT_PATTERN = /(.*?)<\/ulw_verification_attempt_id>/i @@ -37,20 +36,45 @@ export function createToolExecuteAfterHandler(args: { ) => Promise { const { ctx, hooks } = args + // OpenCode injects tool call ids into execute() context and after-hook input via undocumented runtime fields. + // We must treat their identity as a best-effort correlation key, not a guaranteed public contract. + return async ( - input: { tool: string; sessionID: string; callID: string }, + input: { tool: string; sessionID: string; callID?: string; callId?: string; call_id?: string }, output: { title: string; output: string; metadata: Record } | undefined, ): Promise => { if (!output) return - const stored = consumeToolMetadata(input.sessionID, input.callID) + const hookInput = { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id ?? "", + } + + const nativeSessionId = getMetadataString(output.metadata, ["sessionId", "sessionID", "session_id"]) + const stored = recoverToolMetadata(input.sessionID, input) if (stored) { if (stored.title) { output.title = stored.title } if (stored.metadata) { - output.metadata = { ...output.metadata, ...stored.metadata } + if (nativeSessionId) { + log("[tool-execute-after] Native output metadata already includes session linkage; skipping stored metadata overwrite", { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id, + nativeSessionId, + }) + } else { + output.metadata = { ...output.metadata, ...stored.metadata } + } } + } else if (!nativeSessionId) { + log("[tool-execute-after] Unable to recover stored metadata and no native session linkage was present", { + tool: input.tool, + sessionID: input.sessionID, + callID: input.callID ?? input.callId ?? input.call_id, + }) } if (input.tool === "task") { @@ -59,7 +83,9 @@ export function createToolExecuteAfterHandler(args: { const agent = getMetadataString(output.metadata, ["agent"]) const prompt = getMetadataString(output.metadata, ["prompt"]) const verificationAttemptId = prompt?.match(VERIFICATION_ATTEMPT_PATTERN)?.[1]?.trim() - const loopState = directory ? readState(directory) : null + const loopState = directory + ? (await import("../hooks/ralph-loop/storage")).readState(directory) + : null const isVerificationContext = (agent ? stripInvisibleAgentCharacters(agent) : agent) === "oracle" && !!sessionId @@ -83,7 +109,7 @@ export function createToolExecuteAfterHandler(args: { && verificationAttemptId && loopState.verification_attempt_id === verificationAttemptId ) { - writeState(directory, { + ;(await import("../hooks/ralph-loop/storage")).writeState(directory, { ...loopState, verification_session_id: sessionId, }) @@ -93,7 +119,7 @@ export function createToolExecuteAfterHandler(args: { verificationAttemptId, }) } else if (isVerificationContext && !verificationAttemptId) { - writeState(directory, { + ;(await import("../hooks/ralph-loop/storage")).writeState(directory, { ...loopState, verification_session_id: sessionId, }) @@ -108,26 +134,26 @@ export function createToolExecuteAfterHandler(args: { } const runToolExecuteAfterHooks = async (): Promise => { - await hooks.toolOutputTruncator?.["tool.execute.after"]?.(input, output) - await hooks.claudeCodeHooks?.["tool.execute.after"]?.(input, output) - await hooks.preemptiveCompaction?.["tool.execute.after"]?.(input, output) - await hooks.contextWindowMonitor?.["tool.execute.after"]?.(input, output) - await hooks.commentChecker?.["tool.execute.after"]?.(input, output) - await hooks.directoryAgentsInjector?.["tool.execute.after"]?.(input, output) - await hooks.directoryReadmeInjector?.["tool.execute.after"]?.(input, output) - await hooks.rulesInjector?.["tool.execute.after"]?.(input, output) - await hooks.emptyTaskResponseDetector?.["tool.execute.after"]?.(input, output) - await hooks.agentUsageReminder?.["tool.execute.after"]?.(input, output) - await hooks.categorySkillReminder?.["tool.execute.after"]?.(input, output) - await hooks.interactiveBashSession?.["tool.execute.after"]?.(input, output) - await hooks.editErrorRecovery?.["tool.execute.after"]?.(input, output) - await hooks.delegateTaskRetry?.["tool.execute.after"]?.(input, output) - await hooks.atlasHook?.["tool.execute.after"]?.(input, output) - await hooks.taskResumeInfo?.["tool.execute.after"]?.(input, output) - await hooks.readImageResizer?.["tool.execute.after"]?.(input, output) - await hooks.hashlineReadEnhancer?.["tool.execute.after"]?.(input, output) - await hooks.webfetchRedirectGuard?.["tool.execute.after"]?.(input, output) - await hooks.jsonErrorRecovery?.["tool.execute.after"]?.(input, output) + await hooks.toolOutputTruncator?.["tool.execute.after"]?.(hookInput, output) + await hooks.claudeCodeHooks?.["tool.execute.after"]?.(hookInput, output) + await hooks.preemptiveCompaction?.["tool.execute.after"]?.(hookInput, output) + await hooks.contextWindowMonitor?.["tool.execute.after"]?.(hookInput, output) + await hooks.commentChecker?.["tool.execute.after"]?.(hookInput, output) + await hooks.directoryAgentsInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.directoryReadmeInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.rulesInjector?.["tool.execute.after"]?.(hookInput, output) + await hooks.emptyTaskResponseDetector?.["tool.execute.after"]?.(hookInput, output) + await hooks.agentUsageReminder?.["tool.execute.after"]?.(hookInput, output) + await hooks.categorySkillReminder?.["tool.execute.after"]?.(hookInput, output) + await hooks.interactiveBashSession?.["tool.execute.after"]?.(hookInput, output) + await hooks.editErrorRecovery?.["tool.execute.after"]?.(hookInput, output) + await hooks.delegateTaskRetry?.["tool.execute.after"]?.(hookInput, output) + await hooks.atlasHook?.["tool.execute.after"]?.(hookInput, output) + await hooks.taskResumeInfo?.["tool.execute.after"]?.(hookInput, output) + await hooks.readImageResizer?.["tool.execute.after"]?.(hookInput, output) + await hooks.hashlineReadEnhancer?.["tool.execute.after"]?.(hookInput, output) + await hooks.webfetchRedirectGuard?.["tool.execute.after"]?.(hookInput, output) + await hooks.jsonErrorRecovery?.["tool.execute.after"]?.(hookInput, output) } if (input.tool === "extract" || input.tool === "discard") { @@ -146,7 +172,7 @@ export function createToolExecuteAfterHandler(args: { log("[tool-execute-after] Failed to process extract/discard hooks", { tool: input.tool, sessionID: input.sessionID, - callID: input.callID, + callID: input.callID ?? input.callId ?? input.call_id, error, }) } diff --git a/src/plugin/tool-execute-before.test.ts b/src/plugin/tool-execute-before.test.ts index 80daa79a8..76d11a33b 100644 --- a/src/plugin/tool-execute-before.test.ts +++ b/src/plugin/tool-execute-before.test.ts @@ -143,7 +143,7 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("sisyphus-junior") }) - test("resolves subagent_type from session first message when session_id provided without subagent_type", async () => { + test("resolves subagent_type from session first message when task_id is provided without subagent_type", async () => { //#given const ctx = createCtxWithSessionMessages([ { info: { role: "user" } }, @@ -152,7 +152,7 @@ describe("createToolExecuteBeforeHandler", () => { ]) const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } + const output = { args: { task_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } //#when await handler(input, output) @@ -161,6 +161,23 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("explore") }) + test("normalizes task_id into the canonical resume argument", async () => { + //#given + const ctx = createCtxWithSessionMessages([ + { info: { role: "assistant", agent: "oracle" } }, + ]) + const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) + const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } + const output = { args: { task_id: "ses_resume_123", description: "Continue task", prompt: "fix it" } as Record } + + //#when + await handler(input, output) + + //#then + expect(output.args.task_id).toBe("ses_resume_123") + expect(output.args.subagent_type).toBe("oracle") + }) + test("falls back to 'continue' when session has no agent info", async () => { //#given const ctx = createCtxWithSessionMessages([ @@ -169,7 +186,7 @@ describe("createToolExecuteBeforeHandler", () => { ]) const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } + const output = { args: { task_id: "ses_abc123", description: "Continue task", prompt: "fix it" } as Record } //#when await handler(input, output) @@ -178,12 +195,12 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBe("continue") }) - test("preserves subagent_type when session_id is provided with explicit subagent_type", async () => { + test("preserves subagent_type when task_id is provided with explicit subagent_type", async () => { //#given const ctx = createCtxWithSessionMessages() const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) const input = { tool: "task", sessionID: "ses_123", callID: "call_1" } - const output = { args: { session_id: "ses_abc123", subagent_type: "explore", description: "Continue explore" } as Record } + const output = { args: { task_id: "ses_abc123", subagent_type: "explore", description: "Continue explore" } as Record } //#when await handler(input, output) @@ -206,7 +223,7 @@ describe("createToolExecuteBeforeHandler", () => { expect(output.args.subagent_type).toBeUndefined() }) - test("does not set subagent_type when neither category nor session_id is provided and subagent_type is present", async () => { + test("does not set subagent_type when neither category nor task_id is provided and subagent_type is present", async () => { //#given const ctx = createCtxWithSessionMessages() const handler = createToolExecuteBeforeHandler({ ctx, hooks: emptyHooks }) diff --git a/src/plugin/tool-execute-before.ts b/src/plugin/tool-execute-before.ts index 68b1545ea..5c54fba7b 100644 --- a/src/plugin/tool-execute-before.ts +++ b/src/plugin/tool-execute-before.ts @@ -100,12 +100,12 @@ export function createToolExecuteBeforeHandler(args: { const argsObject = output.args const category = typeof argsObject.category === "string" ? argsObject.category : undefined const subagentType = typeof argsObject.subagent_type === "string" ? argsObject.subagent_type : undefined - const sessionId = typeof argsObject.session_id === "string" ? argsObject.session_id : undefined + const taskId = typeof argsObject.task_id === "string" ? argsObject.task_id : undefined if (category) { argsObject.subagent_type = "sisyphus-junior" - } else if (!subagentType && sessionId) { - const resolvedAgent = await resolveSessionAgent(ctx.client, sessionId) + } else if (!subagentType && taskId) { + const resolvedAgent = await resolveSessionAgent(ctx.client, taskId) argsObject.subagent_type = resolvedAgent ?? "continue" } diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 6d04e7e1c..a3e46185a 100644 --- a/src/plugin/tool-registry.ts +++ b/src/plugin/tool-registry.ts @@ -144,7 +144,7 @@ export function trimToolsToCap(filteredTools: ToolsRecord, maxTools: number): vo export function createToolRegistry(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig - managers: Pick + managers: Pick skillContext: SkillContext availableCategories: AvailableCategory[] interactiveBashEnabled?: boolean @@ -170,6 +170,7 @@ export function createToolRegistry(args: { pluginConfig.disabled_agents ?? [], pluginConfig.agents, pluginConfig.categories, + managers.modelFallbackControllerAccessor, ) const isMultimodalLookerEnabled = !(pluginConfig.disabled_agents ?? []).some( @@ -191,6 +192,7 @@ export function createToolRegistry(args: { availableSkills: skillContext.availableSkills, sisyphusAgentConfig: pluginConfig.sisyphus_agent, syncPollTimeoutMs: pluginConfig.background_task?.syncPollTimeoutMs, + modelFallbackControllerAccessor: managers.modelFallbackControllerAccessor, onSyncSessionCreated: async (event) => { log("[index] onSyncSessionCreated callback", { sessionID: event.sessionID, diff --git a/src/plugin/ultrawork-db-model-override.test.ts b/src/plugin/ultrawork-db-model-override.test.ts index ea5646d26..84c7ffed0 100644 --- a/src/plugin/ultrawork-db-model-override.test.ts +++ b/src/plugin/ultrawork-db-model-override.test.ts @@ -112,13 +112,13 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_001", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) //#then const model = readMessageModel("msg_001") - expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }) test("should update variant and thinking fields when variant provided", async () => { @@ -128,7 +128,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_002", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) await flushMicrotasks(5) @@ -144,7 +144,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_nonexistent", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushWithTimeout() @@ -162,13 +162,13 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_003", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) //#then const model = readMessageModel("msg_003") - expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) expect(readMessageField("msg_003", "variant")).toBeNull() expect(readMessageField("msg_003", "thinking")).toBeNull() }) @@ -180,7 +180,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_004", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) @@ -200,7 +200,7 @@ describe("scheduleDeferredModelOverride", () => { //#when scheduleDeferredModelOverride( "msg_corrupt", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, ) await flushMicrotasks(5) diff --git a/src/plugin/ultrawork-model-override.test.ts b/src/plugin/ultrawork-model-override.test.ts index feaf369c1..b37dc1285 100644 --- a/src/plugin/ultrawork-model-override.test.ts +++ b/src/plugin/ultrawork-model-override.test.ts @@ -79,19 +79,19 @@ describe("resolveUltraworkOverride", () => { test("should resolve override when ultrawork keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") //#when const result = resolveUltraworkOverride(config, "sisyphus", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) }) test("should return null when no keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("just do something normal") //#when @@ -103,7 +103,7 @@ describe("resolveUltraworkOverride", () => { test("should return null when agent name is undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something") //#when @@ -115,14 +115,14 @@ describe("resolveUltraworkOverride", () => { test("should use message.agent when input agent is undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", "sisyphus") //#when const result = resolveUltraworkOverride(config, undefined, output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: undefined }) }) test("should return null when agents config is missing", () => { @@ -189,19 +189,19 @@ describe("resolveUltraworkOverride", () => { test("should resolve display name to config key", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ulw do something") //#when const result = resolveUltraworkOverride(config, "Sisyphus - Ultraworker", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) }) test("should handle multiple text parts by joining them", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = { message: {} as Record, parts: [ @@ -215,12 +215,12 @@ describe("resolveUltraworkOverride", () => { const result = resolveUltraworkOverride(config, "sisyphus", output) //#then - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: undefined }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: undefined }) }) test("should use session agent when input and message agents are undefined", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") const getSessionAgentSpy = spyOn(sessionStateModule, "getSessionAgent") getSessionAgentSpy.mockReturnValue("sisyphus") @@ -230,7 +230,7 @@ describe("resolveUltraworkOverride", () => { //#then expect(getSessionAgentSpy).toHaveBeenCalledWith("ses_test") - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }) getSessionAgentSpy.mockRestore() }) @@ -287,7 +287,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should schedule deferred DB override without variant when SDK unavailable", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) const tui = createMockTui() @@ -297,7 +297,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - variant should NOT be applied without SDK validation expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) }) @@ -305,7 +305,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should NOT override variant when SDK unavailable even if config specifies variant", () => { //#given const config = createConfig("sisyphus", { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "extended", }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) @@ -319,7 +319,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - existing variant preserved, not overridden to "extended" expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) expect(output.message["variant"]).toBe("max") @@ -329,7 +329,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should NOT mutate output.message.model when message ID present", () => { //#given const sonnetModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", { existingModel: sonnetModel, messageId: "msg_123", @@ -345,7 +345,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should fall back to direct model mutation without variant when no message ID and no SDK", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something") const tui = createMockTui() @@ -353,7 +353,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { applyUltraworkModelOverrideOnMessage(config, "sisyphus", output, tui) //#then - model is set but variant is NOT applied without SDK validation - expect(output.message.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(output.message.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) expect(output.message["variant"]).toBeUndefined() expect(dbOverrideSpy).not.toHaveBeenCalled() }) @@ -375,7 +375,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should not apply override when no keyword detected", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("just do something normal", { messageId: "msg_123" }) const tui = createMockTui() @@ -388,7 +388,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should log the model transition with deferred DB tag", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const existingModel = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } const output = createOutput("ultrawork do something", { existingModel, @@ -408,7 +408,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should call showToast on override", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) let toastCalled = false const tui = { @@ -426,7 +426,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should resolve display name to config key with deferred path", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ulw do something", { messageId: "msg_123" }) const tui = createMockTui() @@ -436,16 +436,16 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) }) test("should skip override trigger when current model already matches ultrawork model", () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { - existingModel: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + existingModel: { providerID: "anthropic", modelID: "claude-opus-4-7" }, messageId: "msg_123", }) let toastCalled = false @@ -465,13 +465,13 @@ describe("applyUltraworkModelOverrideOnMessage", () => { test("should apply validated variant when SDK confirms model supports it", async () => { //#given - const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-6", variant: "max" }) + const config = createConfig("sisyphus", { model: "anthropic/claude-opus-4-7", variant: "max" }) const output = createOutput("ultrawork do something", { messageId: "msg_123" }) const tui = createMockTui() const mockClient = { provider: { list: async () => ({ - data: { all: [{ id: "anthropic", models: { "claude-opus-4-6": { variants: { max: {} } } } }] }, + data: { all: [{ id: "anthropic", models: { "claude-opus-4-7": { variants: { max: {} } } } }] }, }), }, } @@ -482,7 +482,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { //#then - SDK confirmed max exists, so variant is applied expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) }) diff --git a/src/plugin/ultrawork-variant-availability.test.ts b/src/plugin/ultrawork-variant-availability.test.ts index 1fb8a0910..176603698 100644 --- a/src/plugin/ultrawork-variant-availability.test.ts +++ b/src/plugin/ultrawork-variant-availability.test.ts @@ -23,7 +23,7 @@ describe("resolveValidUltraworkVariant", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { max: {}, high: {}, @@ -35,7 +35,7 @@ describe("resolveValidUltraworkVariant", () => { // when const result = await resolveValidUltraworkVariant( client, - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) @@ -47,7 +47,7 @@ describe("resolveValidUltraworkVariant", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { high: {}, }, @@ -58,7 +58,7 @@ describe("resolveValidUltraworkVariant", () => { // when const result = await resolveValidUltraworkVariant( client, - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, "max", ) @@ -87,7 +87,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { // given const client = createClient({ anthropic: { - "claude-opus-4-6": { + "claude-opus-4-7": { variants: { high: {}, }, @@ -100,7 +100,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { agents: { sisyphus: { ultrawork: { - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", variant: "max", }, }, @@ -130,7 +130,7 @@ describe("applyUltraworkModelOverrideOnMessage variant guard", () => { expect(output.message["thinking"]).toBeUndefined() expect(dbOverrideSpy).toHaveBeenCalledWith( "msg_123", - { providerID: "anthropic", modelID: "claude-opus-4-6" }, + { providerID: "anthropic", modelID: "claude-opus-4-7" }, undefined, ) dbOverrideSpy.mockRestore() diff --git a/src/shared/AGENTS.md b/src/shared/AGENTS.md index 46f178b5b..b6336e6f2 100644 --- a/src/shared/AGENTS.md +++ b/src/shared/AGENTS.md @@ -1,6 +1,6 @@ # src/shared/ — 100+ Utility Files -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW diff --git a/src/shared/agent-config-integration.test.ts b/src/shared/agent-config-integration.test.ts index 6e4726a36..037435b27 100644 --- a/src/shared/agent-config-integration.test.ts +++ b/src/shared/agent-config-integration.test.ts @@ -8,9 +8,9 @@ describe("Agent Config Integration", () => { test("migrates old format agent keys to lowercase", () => { // given - config with old format keys const oldConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6" }, - Atlas: { model: "anthropic/claude-opus-4-6" }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7" }, + Atlas: { model: "anthropic/claude-opus-4-7" }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, "Metis - Plan Consultant": { model: "anthropic/claude-sonnet-4-6" }, "Momus - Plan Critic": { model: "anthropic/claude-sonnet-4-6" }, } @@ -33,9 +33,9 @@ describe("Agent Config Integration", () => { expect(result.migrated).not.toHaveProperty("Momus - Plan Critic") // then - values are preserved - expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-6" }) - expect(result.migrated.atlas).toEqual({ model: "anthropic/claude-opus-4-6" }) - expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-7" }) + expect(result.migrated.atlas).toEqual({ model: "anthropic/claude-opus-4-7" }) + expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-7" }) // then - changed flag is true expect(result.changed).toBe(true) @@ -44,7 +44,7 @@ describe("Agent Config Integration", () => { test("preserves already lowercase keys", () => { // given - config with lowercase keys const config = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, oracle: { model: "openai/gpt-5.4" }, librarian: { model: "opencode/big-pickle" }, } @@ -62,9 +62,9 @@ describe("Agent Config Integration", () => { test("handles mixed case config", () => { // given - config with mixed old and new format const mixedConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7" }, oracle: { model: "openai/gpt-5.4" }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, librarian: { model: "opencode/big-pickle" }, } @@ -173,8 +173,8 @@ describe("Agent Config Integration", () => { test("old config migrates and displays correctly", () => { // given - old format config const oldConfig = { - Sisyphus: { model: "anthropic/claude-opus-4-6", temperature: 0.1 }, - "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-6" }, + Sisyphus: { model: "anthropic/claude-opus-4-7", temperature: 0.1 }, + "Prometheus - Plan Builder": { model: "anthropic/claude-opus-4-7" }, } // when - config is migrated @@ -193,15 +193,15 @@ describe("Agent Config Integration", () => { expect(prometheusDisplay).toBe("Prometheus - Plan Builder") // then - config values are preserved - expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-6", temperature: 0.1 }) - expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-7", temperature: 0.1 }) + expect(result.migrated.prometheus).toEqual({ model: "anthropic/claude-opus-4-7" }) }) test("new config works without migration", () => { // given - new format config (already lowercase) const newConfig = { - sisyphus: { model: "anthropic/claude-opus-4-6" }, - atlas: { model: "anthropic/claude-opus-4-6" }, + sisyphus: { model: "anthropic/claude-opus-4-7" }, + atlas: { model: "anthropic/claude-opus-4-7" }, } // when - migration is applied (should be no-op) diff --git a/src/shared/agent-variant.test.ts b/src/shared/agent-variant.test.ts index 00ef030fb..58bdd193b 100644 --- a/src/shared/agent-variant.test.ts +++ b/src/shared/agent-variant.test.ts @@ -84,14 +84,14 @@ describe("applyAgentVariant", () => { describe("resolveVariantForModel", () => { test("returns agent override variant when configured", () => { - // given - use a model in sisyphus chain (claude-opus-4-6 has default variant "max") + // given - use a model in sisyphus chain (claude-opus-4-7 has default variant "max") // to verify override takes precedence over fallback chain const config = { agents: { sisyphus: { variant: "high" }, }, } as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "sisyphus", model) @@ -103,7 +103,7 @@ describe("resolveVariantForModel", () => { test("returns correct variant for anthropic provider", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "sisyphus", model) @@ -151,7 +151,7 @@ describe("resolveVariantForModel", () => { test("returns undefined for unknown agent", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "nonexistent-agent", model) @@ -203,7 +203,7 @@ describe("resolveVariantForModel", () => { test("returns correct variant for oracle agent with anthropic", () => { // given const config = {} as OhMyOpenCodeConfig - const model = { providerID: "anthropic", modelID: "claude-opus-4-6" } + const model = { providerID: "anthropic", modelID: "claude-opus-4-7" } // when const variant = resolveVariantForModel(config, "oracle", model) diff --git a/src/shared/connected-providers-cache.test.ts b/src/shared/connected-providers-cache.test.ts index 6572a59cc..36abdac26 100644 --- a/src/shared/connected-providers-cache.test.ts +++ b/src/shared/connected-providers-cache.test.ts @@ -61,7 +61,7 @@ describe("updateConnectedProvidersCache", () => { name: "Anthropic", env: [], models: { - "claude-opus-4-6": { id: "claude-opus-4-6", name: "Claude Opus 4.6" }, + "claude-opus-4-7": { id: "claude-opus-4-7", name: "Claude Opus 4.7" }, "claude-sonnet-4-6": { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, }, }, @@ -84,7 +84,7 @@ describe("updateConnectedProvidersCache", () => { { id: "gpt-5.4", name: "GPT-5.4" }, ], anthropic: [ - { id: "claude-opus-4-6", name: "Claude Opus 4.6" }, + { id: "claude-opus-4-7", name: "Claude Opus 4.7" }, { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ], }) diff --git a/src/shared/context-limit-resolver.test.ts b/src/shared/context-limit-resolver.test.ts index a4346a6aa..d924d8a99 100644 --- a/src/shared/context-limit-resolver.test.ts +++ b/src/shared/context-limit-resolver.test.ts @@ -28,15 +28,15 @@ describe("resolveActualContextLimit", () => { resetContextLimitEnv() }) - it("returns cached limit for Anthropic 4.6 models when 1M mode is disabled (GA support)", () => { + it("returns cached limit for Anthropic 4.7 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-opus-4-6", 1_000_000) + modelContextLimitsCache.set("anthropic/claude-opus-4-7", 1_000_000) // when - const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-6", { + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4-7", { anthropicContext1MEnabled: false, modelContextLimitsCache, }) @@ -107,15 +107,15 @@ describe("resolveActualContextLimit", () => { expect(actualLimit).toBe(200000) }) - it("supports Anthropic 4.6 dot-version model IDs without explicit 1M mode", () => { + it("supports Anthropic 4.7 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) + modelContextLimitsCache.set("anthropic/claude-opus-4.7", 1_000_000) // when - const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.6", { + const actualLimit = resolveActualContextLimit("anthropic", "claude-opus-4.7", { anthropicContext1MEnabled: false, modelContextLimitsCache, }) diff --git a/src/shared/context-limit-resolver.ts b/src/shared/context-limit-resolver.ts index 2bf2a8147..2d440658b 100644 --- a/src/shared/context-limit-resolver.ts +++ b/src/shared/context-limit-resolver.ts @@ -20,7 +20,7 @@ function getAnthropicActualLimit(modelCacheState?: ContextLimitModelCacheState): } function supportsCachedAnthropicLimit(modelID: string): boolean { - return /^claude-(opus|sonnet)-4(?:-|\.)6(?:-high)?$/.test(modelID) + return /^claude-(opus|sonnet)-4(?:-|\.)(?:6|7)(?:-high)?$/.test(modelID) } export function resolveActualContextLimit( diff --git a/src/shared/excluded-dirs.test.ts b/src/shared/excluded-dirs.test.ts new file mode 100644 index 000000000..21a488907 --- /dev/null +++ b/src/shared/excluded-dirs.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test } from "bun:test" +import { EXCLUDED_DIRS } from "./excluded-dirs" +import { EXCLUDED_DIRS as EXCLUDED_DIRS_FROM_BARREL } from "." + +describe("EXCLUDED_DIRS", () => { + test("contains the well-known junk directories we never want to recurse into", () => { + // given + const expected = [ + "node_modules", + ".git", + "dist", + "build", + ".next", + ".sisyphus", + ".omx", + ".turbo", + "coverage", + "out", + ".cache", + ".vscode-test", + "target", + ".local-ignore", + ] + + // when / then + for (const name of expected) { + expect(EXCLUDED_DIRS.has(name)).toBe(true) + } + }) + + test("does not contain commonly-wanted project directories", () => { + // given + const shouldBeAllowed = ["src", "lib", "tests", "test", "docs", ".github", ".cursor", ".claude", ".opencode"] + + // when / then + for (const name of shouldBeAllowed) { + expect(EXCLUDED_DIRS.has(name)).toBe(false) + } + }) + + test("is frozen so consumers cannot mutate shared state", () => { + // given / when / then + expect(Object.isFrozen(EXCLUDED_DIRS)).toBe(true) + }) + + test("is re-exported from the shared barrel", () => { + // given / when / then + expect(EXCLUDED_DIRS_FROM_BARREL).toBe(EXCLUDED_DIRS) + }) +}) diff --git a/src/shared/excluded-dirs.ts b/src/shared/excluded-dirs.ts new file mode 100644 index 000000000..059a01406 --- /dev/null +++ b/src/shared/excluded-dirs.ts @@ -0,0 +1,18 @@ +const EXCLUDED_DIR_NAMES = [ + "node_modules", + ".git", + "dist", + "build", + ".next", + ".sisyphus", + ".omx", + ".turbo", + "coverage", + "out", + ".cache", + ".vscode-test", + "target", + ".local-ignore", +] as const + +export const EXCLUDED_DIRS: ReadonlySet = Object.freeze(new Set(EXCLUDED_DIR_NAMES)) diff --git a/src/shared/index.ts b/src/shared/index.ts index 826434d42..e99234c33 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -57,6 +57,7 @@ export * from "./session-utils" export * from "./tmux" export * from "./model-suggestion-retry" export * from "./opencode-server-auth" +export * from "./opencode-provider-auth" export * from "./opencode-http-api" export * from "./port-utils" export * from "./git-worktree" @@ -77,3 +78,5 @@ export * from "./plugin-identity" export * from "./log-legacy-plugin-startup-warning" export * from "./task-system-enabled" export * from "./parse-tools-config" +export { parseModelString } from "./model-string-parser" +export { EXCLUDED_DIRS } from "./excluded-dirs" diff --git a/src/shared/jsonc-parser.memoization.test.ts b/src/shared/jsonc-parser.memoization.test.ts new file mode 100644 index 000000000..c4cd1f5b8 --- /dev/null +++ b/src/shared/jsonc-parser.memoization.test.ts @@ -0,0 +1,54 @@ +import { afterEach, describe, expect, mock, spyOn, test } from "bun:test" +import * as fs from "node:fs" +import { join } from "node:path" + +describe("detectPluginConfigFile memoization", () => { + const testDir = join(__dirname, ".test-detect-plugin-memoization") + + afterEach(() => { + mock.restore() + }) + + test("returns cached result on repeated calls for the same directory", async () => { + // given + const existsSync = spyOn(fs, "existsSync").mockImplementation((filePath: fs.PathLike) => { + return String(filePath).endsWith("oh-my-openagent.jsonc") + }) + const readdirSync = spyOn(fs, "readdirSync").mockImplementation(() => []) + spyOn(fs, "readFileSync").mockImplementation(() => "") + + const parserModule = await import(`./jsonc-parser?memoization=${Date.now()}-${Math.random()}`) + + // when + const firstResult = parserModule.detectPluginConfigFile(testDir) + const callsAfterFirstResult = existsSync.mock.calls.length + const secondResult = parserModule.detectPluginConfigFile(testDir) + + // then + expect(firstResult).toEqual(secondResult) + expect(existsSync.mock.calls.length).toBe(callsAfterFirstResult) + expect(readdirSync).toHaveBeenCalledTimes(0) + }) + + test("clears cached result when requested", async () => { + // given + const existsSync = spyOn(fs, "existsSync").mockImplementation((filePath: fs.PathLike) => { + return String(filePath).endsWith("oh-my-openagent.jsonc") + }) + const readdirSync = spyOn(fs, "readdirSync").mockImplementation(() => []) + spyOn(fs, "readFileSync").mockImplementation(() => "") + + const parserModule = await import(`./jsonc-parser?memoization=${Date.now()}-${Math.random()}`) + + parserModule.detectPluginConfigFile(testDir) + parserModule.clearPluginConfigFileDetectionCache() + const callsAfterClear = existsSync.mock.calls.length + + // when + parserModule.detectPluginConfigFile(testDir) + + // then + expect(existsSync.mock.calls.length).toBeGreaterThan(callsAfterClear) + expect(readdirSync).toHaveBeenCalledTimes(0) + }) +}) diff --git a/src/shared/jsonc-parser.test.ts b/src/shared/jsonc-parser.test.ts index 279db1fc5..c06e36353 100644 --- a/src/shared/jsonc-parser.test.ts +++ b/src/shared/jsonc-parser.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, test } from "bun:test" -import { detectConfigFile, detectPluginConfigFile, parseJsonc, parseJsoncSafe, readJsoncFile } from "./jsonc-parser" +import { afterEach, beforeEach, describe, expect, test } from "bun:test" +import { clearPluginConfigFileDetectionCache, detectConfigFile, detectPluginConfigFile, parseJsonc, parseJsoncSafe, readJsoncFile } from "./jsonc-parser" import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { join } from "node:path" @@ -330,6 +330,14 @@ describe("detectConfigFile", () => { describe("detectPluginConfigFile", () => { const testDir = join(__dirname, ".test-detect-plugin") + beforeEach(() => { + clearPluginConfigFileDetectionCache() + }) + + afterEach(() => { + clearPluginConfigFileDetectionCache() + }) + test("prefers oh-my-openagent over oh-my-opencode when both jsonc files exist", () => { // given if (!existsSync(testDir)) mkdirSync(testDir, { recursive: true }) diff --git a/src/shared/jsonc-parser.ts b/src/shared/jsonc-parser.ts index da1e0d98c..bb7148983 100644 --- a/src/shared/jsonc-parser.ts +++ b/src/shared/jsonc-parser.ts @@ -9,6 +9,14 @@ export interface JsoncParseResult { errors: Array<{ message: string; offset: number; length: number }> } +type DetectPluginConfigResult = { + format: "json" | "jsonc" | "none" + path: string + legacyPath?: string +} + +const pluginConfigFileDetectionCache = new Map() + function stripBom(content: string): string { return content.charCodeAt(0) === 0xfeff ? content.slice(1) : content } @@ -75,24 +83,34 @@ export function detectConfigFile(basePath: string): { return { format: "none", path: jsonPath } } -export function detectPluginConfigFile(dir: string): { - format: "json" | "jsonc" | "none" - path: string - legacyPath?: string -} { +export function clearPluginConfigFileDetectionCache(): void { + pluginConfigFileDetectionCache.clear() +} + +export function detectPluginConfigFile(dir: string): DetectPluginConfigResult { + const cachedResult = pluginConfigFileDetectionCache.get(dir) + + if (cachedResult !== undefined) { + return cachedResult + } + const canonicalResult = detectConfigFile(join(dir, CONFIG_BASENAME)) const legacyResult = detectConfigFile(join(dir, LEGACY_CONFIG_BASENAME)) + let detectionResult: DetectPluginConfigResult + if (canonicalResult.format !== "none") { - return { + detectionResult = { ...canonicalResult, legacyPath: legacyResult.format !== "none" ? legacyResult.path : undefined, } + } else if (legacyResult.format !== "none") { + detectionResult = legacyResult + } else { + detectionResult = { format: "none", path: join(dir, `${CONFIG_BASENAME}.json`) } } - if (legacyResult.format !== "none") { - return legacyResult - } + pluginConfigFileDetectionCache.set(dir, detectionResult) - return { format: "none", path: join(dir, `${CONFIG_BASENAME}.json`) } + return detectionResult } diff --git a/src/shared/load-opencode-plugins.test.ts b/src/shared/load-opencode-plugins.test.ts new file mode 100644 index 000000000..9723c1cd3 --- /dev/null +++ b/src/shared/load-opencode-plugins.test.ts @@ -0,0 +1,89 @@ +/// + +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test" +import * as fs from "node:fs" + +type LoadOpencodePluginsModule = { + loadOpencodePlugins: (directory: string) => string[] + clearOpencodePluginsCache?: () => void +} + +const existsSyncMock = mock((_path: string) => true) +const readFileSyncMock = mock((_path: string, _encoding?: string) => `{ + "plugin": ["plugin-a", "plugin-b"] +}`) + +async function importFreshLoadOpencodePluginsModule(): Promise { + const modulePath = `${new URL("./load-opencode-plugins.ts", import.meta.url).pathname}?test=${Date.now()}-${Math.random()}` + return import(modulePath) +} + +describe("loadOpencodePlugins", () => { + beforeEach(() => { + existsSyncMock.mockReset() + existsSyncMock.mockImplementation((_path: string) => true) + readFileSyncMock.mockReset() + readFileSyncMock.mockImplementation((_path: string, _encoding?: string) => `{ + "plugin": ["plugin-a", "plugin-b"] +}`) + + mock.module("node:fs", () => ({ + ...fs, + existsSync: existsSyncMock, + readFileSync: readFileSyncMock, + })) + }) + + afterEach(() => { + mock.restore() + }) + + describe("#given the same directory is loaded twice", () => { + describe("#when loading plugins repeatedly", () => { + it("#then does not call readFileSync on the second load", async () => { + // given + const { loadOpencodePlugins } = await importFreshLoadOpencodePluginsModule() + + // when + const firstResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterFirstLoad = readFileSyncMock.mock.calls.length + const secondResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterSecondLoad = readFileSyncMock.mock.calls.length + + // then + expect(firstResult).toEqual(["plugin-a", "plugin-b"]) + expect(secondResult).toEqual(["plugin-a", "plugin-b"]) + expect(readCountAfterFirstLoad).toBeGreaterThan(0) + expect(readCountAfterSecondLoad - readCountAfterFirstLoad).toBe(0) + }) + }) + }) + + describe("#given the plugin cache was cleared", () => { + describe("#when loading the same directory again", () => { + it("#then re-reads plugin config files from disk", async () => { + // given + const { loadOpencodePlugins, clearOpencodePluginsCache } = await importFreshLoadOpencodePluginsModule() + + if (typeof clearOpencodePluginsCache !== "function") { + throw new Error("clearOpencodePluginsCache export is missing") + } + + // when + const firstResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterFirstLoad = readFileSyncMock.mock.calls.length + loadOpencodePlugins("/some/fake/dir") + const readCountAfterSecondLoad = readFileSyncMock.mock.calls.length + clearOpencodePluginsCache() + const thirdResult = loadOpencodePlugins("/some/fake/dir") + const readCountAfterThirdLoad = readFileSyncMock.mock.calls.length + + // then + expect(firstResult).toEqual(["plugin-a", "plugin-b"]) + expect(thirdResult).toEqual(["plugin-a", "plugin-b"]) + expect(readCountAfterSecondLoad - readCountAfterFirstLoad).toBe(0) + expect(readCountAfterThirdLoad - readCountAfterSecondLoad).toBeGreaterThan(0) + }) + }) + }) +}) diff --git a/src/shared/load-opencode-plugins.ts b/src/shared/load-opencode-plugins.ts index 5517c74b1..a6beffdcf 100644 --- a/src/shared/load-opencode-plugins.ts +++ b/src/shared/load-opencode-plugins.ts @@ -8,6 +8,8 @@ interface OpencodeConfig { plugin?: (string | [string, ...unknown[]])[] } +const opencodePluginsCache = new Map() + function getWindowsAppdataDir(): string | null { return process.env.APPDATA || null } @@ -33,6 +35,11 @@ function getConfigPaths(directory: string): string[] { } export function loadOpencodePlugins(directory: string): string[] { + const cachedPluginEntries = opencodePluginsCache.get(directory) + if (cachedPluginEntries) { + return cachedPluginEntries + } + const pluginEntries: string[] = [] const seenPluginEntries = new Set() @@ -56,5 +63,10 @@ export function loadOpencodePlugins(directory: string): string[] { } } + opencodePluginsCache.set(directory, pluginEntries) return pluginEntries } + +export function clearOpencodePluginsCache(): void { + opencodePluginsCache.clear() +} diff --git a/src/shared/log-legacy-plugin-startup-warning.test.ts b/src/shared/log-legacy-plugin-startup-warning.test.ts index 917f40927..76ec3541f 100644 --- a/src/shared/log-legacy-plugin-startup-warning.test.ts +++ b/src/shared/log-legacy-plugin-startup-warning.test.ts @@ -63,7 +63,7 @@ describe("logLegacyPluginStartupWarning", () => { //#then expect(mockLog).toHaveBeenCalledTimes(1) expect(mockLog).toHaveBeenCalledWith( - "[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", + "[legacy-migration] 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"], diff --git a/src/shared/log-legacy-plugin-startup-warning.ts b/src/shared/log-legacy-plugin-startup-warning.ts index cc8be67e2..d1151b122 100644 --- a/src/shared/log-legacy-plugin-startup-warning.ts +++ b/src/shared/log-legacy-plugin-startup-warning.ts @@ -22,7 +22,7 @@ export function logLegacyPluginStartupWarning(deps: LogLegacyPluginStartupWarnin const suggestedEntries = result.legacyEntries.map(toCanonicalEntry) - logFn("[OhMyOpenCodePlugin] Legacy plugin entry detected in OpenCode config", { + logFn("[legacy-migration] Legacy plugin entry detected in OpenCode config", { legacyEntries: result.legacyEntries, suggestedEntries, hasCanonicalEntry: result.hasCanonicalEntry, diff --git a/src/shared/merge-categories.test.ts b/src/shared/merge-categories.test.ts index c2f56aaa5..5ed82b465 100644 --- a/src/shared/merge-categories.test.ts +++ b/src/shared/merge-categories.test.ts @@ -71,7 +71,7 @@ describe("mergeCategories", () => { it("user overrides merge with defaults", () => { //#given const userCategories = { - "ultrabrain": { model: "anthropic/claude-opus-4-6" }, + "ultrabrain": { model: "anthropic/claude-opus-4-7" }, } //#when @@ -79,6 +79,6 @@ describe("mergeCategories", () => { //#then expect(result["ultrabrain"]).toBeDefined() - expect(result["ultrabrain"].model).toBe("anthropic/claude-opus-4-6") + expect(result["ultrabrain"].model).toBe("anthropic/claude-opus-4-7") }) }) diff --git a/src/shared/migration.test.ts b/src/shared/migration.test.ts index e0b5f2808..072858d7c 100644 --- a/src/shared/migration.test.ts +++ b/src/shared/migration.test.ts @@ -19,7 +19,7 @@ describe("migrateAgentNames", () => { test("migrates legacy OmO names to lowercase", () => { // given: Config with legacy OmO agent names const agents = { - omo: { model: "anthropic/claude-opus-4-6" }, + omo: { model: "anthropic/claude-opus-4-7" }, OmO: { temperature: 0.5 }, "OmO-Plan": { prompt: "custom prompt" }, } @@ -88,7 +88,7 @@ describe("migrateAgentNames", () => { test("migrates orchestrator-sisyphus to atlas", () => { // given: Config with legacy orchestrator-sisyphus agent name const agents = { - "orchestrator-sisyphus": { model: "anthropic/claude-opus-4-6" }, + "orchestrator-sisyphus": { model: "anthropic/claude-opus-4-7" }, } // when: Migrate agent names @@ -96,14 +96,14 @@ describe("migrateAgentNames", () => { // then: orchestrator-sisyphus should be migrated to atlas expect(changed).toBe(true) - expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-7" }) expect(migrated["orchestrator-sisyphus"]).toBeUndefined() }) test("migrates lowercase atlas to atlas", () => { // given: Config with lowercase atlas agent name const agents = { - atlas: { model: "anthropic/claude-opus-4-6" }, + atlas: { model: "anthropic/claude-opus-4-7" }, } // when: Migrate agent names @@ -111,7 +111,7 @@ describe("migrateAgentNames", () => { // then: lowercase atlas should remain atlas (no change needed) expect(changed).toBe(false) - expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-6" }) + expect(migrated["atlas"]).toEqual({ model: "anthropic/claude-opus-4-7" }) }) test("migrates Sisyphus variants to lowercase", () => { @@ -524,7 +524,7 @@ describe("migrateConfigFile", () => { // then: Model version should be migrated expect(needsWrite).toBe(true) const categories = rawConfig.categories as Record> - expect(categories["my-category"].model).toBe("anthropic/claude-opus-4-6") + expect(categories["my-category"].model).toBe("anthropic/claude-opus-4-7") }) test("does not set needsWrite when no model versions need migration", () => { @@ -534,7 +534,7 @@ describe("migrateConfigFile", () => { sisyphus: { model: "openai/gpt-5.4-codex" }, }, categories: { - "my-category": { model: "anthropic/claude-opus-4-6" }, + "my-category": { model: "anthropic/claude-opus-4-7" }, }, } @@ -572,10 +572,10 @@ describe("MODEL_VERSION_MAP", () => { expect(MODEL_VERSION_MAP["openai/gpt-5.4-codex"]).toBeUndefined() }) - test("maps anthropic/claude-opus-4-5 to anthropic/claude-opus-4-6", () => { + test("maps anthropic/claude-opus-4-5 to anthropic/claude-opus-4-7", () => { // given/when: Check MODEL_VERSION_MAP // then: Should contain correct mapping - expect(MODEL_VERSION_MAP["anthropic/claude-opus-4-5"]).toBe("anthropic/claude-opus-4-6") + expect(MODEL_VERSION_MAP["anthropic/claude-opus-4-5"]).toBe("anthropic/claude-opus-4-7") }) test("maps openai/gpt-5.3-codex to openai/gpt-5.4 for deep category migration", () => { @@ -614,7 +614,7 @@ describe("migrateModelVersions", () => { // then: Model should be updated expect(changed).toBe(true) const prometheus = migrated["prometheus"] as Record - expect(prometheus.model).toBe("anthropic/claude-opus-4-6") + expect(prometheus.model).toBe("anthropic/claude-opus-4-7") }) test("leaves unknown model strings untouched", () => { @@ -674,7 +674,7 @@ describe("migrateModelVersions", () => { // then: Only mapped models should be updated expect(changed).toBe(true) expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-7") expect((migrated["oracle"] as Record).model).toBe("openai/gpt-5.4") }) @@ -736,9 +736,9 @@ describe("migrateModelVersions", () => { // then: Only prometheus should be migrated expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"]) + expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"]) expect((migrated["sisyphus"] as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated["prometheus"] as Record).model).toBe("anthropic/claude-opus-4-7") }) test("backward compatible without appliedMigrations param", () => { @@ -820,12 +820,12 @@ describe("migrateConfigFile _migrations tracking", () => { // (legacy + new) is written to the sidecar file exactly once. expect(result).toBe(true) expect(rawConfig._migrations).toBeUndefined() - expect((rawConfig.agents as Record>).prometheus.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).prometheus.model).toBe("anthropic/claude-opus-4-7") const sidecar = JSON.parse(fs.readFileSync(`${configPath}.migrations.json`, "utf-8")) expect(new Set(sidecar.appliedMigrations)).toEqual(new Set([ "model-version:openai/gpt-5.4-codex->openai/gpt-5.3-codex", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ])) // cleanup @@ -890,7 +890,7 @@ describe("migrateAgentConfigToCategory", () => { { model: "google/gemini-3-flash" }, { model: "openai/gpt-5.4" }, { model: "anthropic/claude-haiku-4-5" }, - { model: "anthropic/claude-opus-4-6" }, + { model: "anthropic/claude-opus-4-7" }, { model: "anthropic/claude-sonnet-4-6" }, ] @@ -970,7 +970,7 @@ describe("shouldDeleteAgentConfig", () => { // given: Config with custom model override const config = { category: "visual-engineering", - model: "anthropic/claude-opus-4-6", + model: "anthropic/claude-opus-4-7", } // when: Check if config should be deleted @@ -1245,9 +1245,9 @@ describe("migrateModelVersions with applied migrations", () => { // then: Skip sisyphus (already applied), apply oracle expect(changed).toBe(true) - expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"]) + expect(newMigrations).toEqual(["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"]) expect((migrated.sisyphus as Record).model).toBe("openai/gpt-5.4-codex") - expect((migrated.oracle as Record).model).toBe("anthropic/claude-opus-4-6") + expect((migrated.oracle as Record).model).toBe("anthropic/claude-opus-4-7") }) test("backward compatible: no appliedMigrations param", () => { @@ -1334,12 +1334,12 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => const needsWrite = migrateConfigFile(testConfigPath, rawConfig) expect(needsWrite).toBe(true) - expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-7") expect(rawConfig._migrations).toBeUndefined() const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(sidecar.appliedMigrations).toEqual([ - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ]) }) @@ -1408,7 +1408,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => JSON.stringify({ appliedMigrations: [ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ], }), ) @@ -1416,7 +1416,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => agents: { oracle: { model: "anthropic/claude-opus-4-5" }, }, - _migrations: ["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6"], + _migrations: ["model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7"], } fs.writeFileSync(testConfigPath, JSON.stringify(rawConfig, null, 2)) @@ -1430,7 +1430,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(sidecar.appliedMigrations).toEqual([ - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", ]) }) @@ -1460,13 +1460,13 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => // codex was reverted, must stay expect((rawConfig.agents as Record>).codex.model).toBe("openai/gpt-5.3-codex") // claude migrates - expect((rawConfig.agents as Record>).claude.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).claude.model).toBe("anthropic/claude-opus-4-7") expect(rawConfig._migrations).toBeUndefined() const sidecar = JSON.parse(fs.readFileSync(sidecarPath(testConfigPath), "utf-8")) expect(new Set(sidecar.appliedMigrations)).toEqual(new Set([ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ])) }) @@ -1494,7 +1494,7 @@ describe("migrateConfigFile with migration tracking via sidecar (#3263)", () => expect(Array.isArray(migrations)).toBe(true) expect(migrations).toContain("model-version:openai/gpt-5.3-codex->openai/gpt-5.4") expect(migrations.length).toBeGreaterThanOrEqual(1) - expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-6") + expect((rawConfig.agents as Record>).oracle.model).toBe("anthropic/claude-opus-4-7") // Sidecar should not exist because write failed expect(fs.existsSync(sidecarPath(testConfigPath))).toBe(false) diff --git a/src/shared/migration/agent-category.ts b/src/shared/migration/agent-category.ts index 6f75682ca..f3ddf291a 100644 --- a/src/shared/migration/agent-category.ts +++ b/src/shared/migration/agent-category.ts @@ -17,6 +17,7 @@ export const MODEL_TO_CATEGORY_MAP: Record = { "openai/gpt-5.4": "ultrabrain", "anthropic/claude-haiku-4-5": "quick", "anthropic/claude-opus-4-6": "unspecified-high", + "anthropic/claude-opus-4-7": "unspecified-high", "anthropic/claude-sonnet-4-6": "unspecified-low", } diff --git a/src/shared/migration/config-migration.test.ts b/src/shared/migration/config-migration.test.ts index 35f8b574a..ff59d7ca3 100644 --- a/src/shared/migration/config-migration.test.ts +++ b/src/shared/migration/config-migration.test.ts @@ -8,7 +8,7 @@ import { migrateConfigFile } from "./config-migration" import { getSidecarPath } from "./migrations-sidecar" const createdDirectories: string[] = [] -const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6" +const MIGRATION_KEY = "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7" function createWorkdir(): string { const workdir = mkdtempSync(join(tmpdir(), "omo-config-migration-")) @@ -46,13 +46,13 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(needsWrite).toBe(true) expect(rawConfig._migrations).toBeUndefined() expect((rawConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record expect(persistedConfig._migrations).toBeUndefined() expect((persistedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const sidecar = JSON.parse(readFileSync(getSidecarPath(configPath), "utf-8")) as { @@ -87,7 +87,7 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(retriedNeedsWrite).toBe(true) expect(retriedConfig._migrations).toBeUndefined() expect((retriedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) expect(existsSync(getSidecarPath(configPath))).toBe(true) }) @@ -108,13 +108,13 @@ describe("migrateConfigFile sidecar write ordering", () => { expect(needsWrite).toBe(true) expect(rawConfig._migrations).toEqual([MIGRATION_KEY]) expect((rawConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) const persistedConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record expect(persistedConfig._migrations).toEqual([MIGRATION_KEY]) expect((persistedConfig.agents as Record>).prometheus.model).toBe( - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ) expect(statSync(getSidecarPath(configPath)).isDirectory()).toBe(true) }) diff --git a/src/shared/migration/migrations-sidecar.test.ts b/src/shared/migration/migrations-sidecar.test.ts index 5809bde94..503ea9105 100644 --- a/src/shared/migration/migrations-sidecar.test.ts +++ b/src/shared/migration/migrations-sidecar.test.ts @@ -42,7 +42,7 @@ describe("migrations sidecar", () => { JSON.stringify({ appliedMigrations: [ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ], }), ) @@ -51,7 +51,7 @@ describe("migrations sidecar", () => { expect(applied.size).toBe(2) expect(applied.has("model-version:openai/gpt-5.3-codex->openai/gpt-5.4")).toBe(true) - expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6")).toBe(true) + expect(applied.has("model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7")).toBe(true) }) test("returns an empty set on malformed JSON instead of throwing", () => { @@ -134,7 +134,7 @@ describe("migrations sidecar", () => { const configPath = join(workdir, "oh-my-openagent.jsonc") const original = new Set([ "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6", + "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7", ]) writeAppliedMigrations(configPath, original) diff --git a/src/shared/migration/migrations-sidecar.ts b/src/shared/migration/migrations-sidecar.ts index cd0088922..0cbac7db1 100644 --- a/src/shared/migration/migrations-sidecar.ts +++ b/src/shared/migration/migrations-sidecar.ts @@ -22,7 +22,7 @@ import { writeFileAtomically } from "../write-file-atomically" * { * "appliedMigrations": [ * "model-version:openai/gpt-5.3-codex->openai/gpt-5.4", - * "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-6" + * "model-version:anthropic/claude-opus-4-5->anthropic/claude-opus-4-7" * ] * } */ diff --git a/src/shared/migration/model-versions.ts b/src/shared/migration/model-versions.ts index 13731dcaa..40aee07b3 100644 --- a/src/shared/migration/model-versions.ts +++ b/src/shared/migration/model-versions.ts @@ -6,7 +6,8 @@ * Keys are full "provider/model" strings. Only openai and anthropic entries needed. */ export const MODEL_VERSION_MAP: Record = { - "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-7", + "anthropic/claude-opus-4-6": "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-5": "anthropic/claude-sonnet-4-6", "openai/gpt-5.3-codex": "openai/gpt-5.4", } diff --git a/src/shared/model-availability.test.ts b/src/shared/model-availability.test.ts index 7be5e363c..77ca0ca14 100644 --- a/src/shared/model-availability.test.ts +++ b/src/shared/model-availability.test.ts @@ -65,7 +65,7 @@ describe("fetchAvailableModels", () => { it("#given cache file with models #when fetchAvailableModels called with connectedProviders #then returns Set of model IDs", async () => { writeModelsCache({ openai: { id: "openai", models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { id: "anthropic", models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { id: "anthropic", models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { id: "google", models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -76,7 +76,7 @@ describe("fetchAvailableModels", () => { expect(result).toBeInstanceOf(Set) expect(result.size).toBe(3) expect(result.has("openai/gpt-5.4")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("google/gemini-3.1-pro")).toBe(true) }) @@ -145,7 +145,7 @@ describe("fetchAvailableModels", () => { it("#given cache read twice #when second call made with same providers #then reads fresh each time", async () => { writeModelsCache({ openai: { id: "openai", models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { id: "anthropic", models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { id: "anthropic", models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result1 = await fetchAvailableModels(undefined, { connectedProviders: ["openai"] }) @@ -192,7 +192,7 @@ describe("fuzzyMatchModel", () => { const available = new Set([ "openai/gpt-5.4", "openai/gpt-5.3-codex", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("gpt-5.4", available) expect(result).toBe("openai/gpt-5.4") @@ -239,25 +239,25 @@ describe("fuzzyMatchModel", () => { // given available models with claude variants // when searching for claude-opus // then return matching claude-opus model - it("should match claude-opus to claude-opus-4-6", () => { + it("should match claude-opus to claude-opus-4-7", () => { const available = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", ]) const result = fuzzyMatchModel("claude-opus", available) - expect(result).toBe("anthropic/claude-opus-4-6") + expect(result).toBe("anthropic/claude-opus-4-7") }) // given github-copilot serves claude versions with dot notation // when fallback chain uses hyphen notation in requested model // then normalize both forms and match github-copilot model - it("should match github-copilot claude-opus-4-6 to claude-opus-4.6", () => { + it("should match github-copilot claude-opus-4-7 to claude-opus-4.7", () => { const available = new Set([ - "github-copilot/claude-opus-4.6", + "github-copilot/claude-opus-4.7", "opencode/big-pickle", ]) - const result = fuzzyMatchModel("claude-opus-4-6", available, ["github-copilot"]) - expect(result).toBe("github-copilot/claude-opus-4.6") + const result = fuzzyMatchModel("claude-opus-4-7", available, ["github-copilot"]) + expect(result).toBe("github-copilot/claude-opus-4.7") }) // given claude models can evolve to newer version numbers @@ -275,7 +275,7 @@ describe("fuzzyMatchModel", () => { it("should filter by provider when providers array is given", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "google/gemini-3", ]) const result = fuzzyMatchModel("gpt", available, ["openai"]) @@ -288,7 +288,7 @@ describe("fuzzyMatchModel", () => { it("should return null when provider filter excludes all matches", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("claude", available, ["openai"]) expect(result).toBeNull() @@ -300,7 +300,7 @@ describe("fuzzyMatchModel", () => { it("should return null when no match found", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("gemini", available) expect(result).toBeNull() @@ -312,7 +312,7 @@ describe("fuzzyMatchModel", () => { it("should match case-insensitively", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) const result = fuzzyMatchModel("GPT-5.4", available) expect(result).toBe("openai/gpt-5.4") @@ -323,11 +323,11 @@ describe("fuzzyMatchModel", () => { // then return exact match first it("should prioritize exact match over longer variants", () => { const available = new Set([ - "anthropic/claude-opus-4-6", - "anthropic/claude-opus-4-6-extended", + "anthropic/claude-opus-4-7", + "anthropic/claude-opus-4-7-extended", ]) - const result = fuzzyMatchModel("claude-opus-4-6", available) - expect(result).toBe("anthropic/claude-opus-4-6") + const result = fuzzyMatchModel("claude-opus-4-7", available) + expect(result).toBe("anthropic/claude-opus-4-7") }) // given available models with similar model IDs (e.g., glm-5 and big-pickle) @@ -372,7 +372,7 @@ describe("fuzzyMatchModel", () => { it("should search all specified providers", () => { const available = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "google/gemini-3", ]) const result = fuzzyMatchModel("gpt", available, ["openai", "google"]) @@ -520,7 +520,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should filter models by connected providers", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -529,7 +529,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(1) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("openai/gpt-5.4")).toBe(false) expect(result.has("google/gemini-3.1-pro")).toBe(false) }) @@ -540,7 +540,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should filter models by multiple connected providers", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, google: { models: { "gemini-3.1-pro": { id: "gemini-3.1-pro" } } }, }) @@ -549,7 +549,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(2) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("google/gemini-3.1-pro")).toBe(true) expect(result.has("openai/gpt-5.4")).toBe(false) }) @@ -560,7 +560,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return empty set when connectedProviders is empty", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels(undefined, { @@ -576,7 +576,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return empty set when connectedProviders not specified", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels() @@ -605,7 +605,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should return models from providers that exist in both cache and connected list", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) const result = await fetchAvailableModels(undefined, { @@ -613,7 +613,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { }) expect(result.size).toBe(1) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) }) // given filtered fetch @@ -622,7 +622,7 @@ describe("fetchAvailableModels with connected providers filtering", () => { it("should not cache filtered results", async () => { writeModelsCache({ openai: { models: { "gpt-5.4": { id: "gpt-5.4" } } }, - anthropic: { models: { "claude-opus-4-6": { id: "claude-opus-4-6" } } }, + anthropic: { models: { "claude-opus-4-7": { id: "claude-opus-4-7" } } }, }) // First call with anthropic @@ -706,13 +706,13 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", writeProviderModelsCache({ models: { opencode: ["big-pickle", "gpt-5-nano"], - anthropic: ["claude-opus-4-6"] + anthropic: ["claude-opus-4-7"] }, connected: ["opencode", "anthropic"] }) writeModelsCache({ opencode: { models: { "big-pickle": {}, "gpt-5-nano": {}, "gpt-5.4": {} } }, - anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } } + anthropic: { models: { "claude-opus-4-7": {}, "claude-sonnet-4-6": {} } } }) const result = await fetchAvailableModels(undefined, { @@ -722,7 +722,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", expect(result.size).toBe(3) expect(result.has("opencode/big-pickle")).toBe(true) expect(result.has("opencode/gpt-5-nano")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("opencode/gpt-5.4")).toBe(false) expect(result.has("anthropic/claude-sonnet-4-6")).toBe(false) }) @@ -773,7 +773,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", writeProviderModelsCache({ models: { opencode: ["big-pickle"], - anthropic: ["claude-opus-4-6"], + anthropic: ["claude-opus-4-7"], google: ["gemini-3.1-pro"] }, connected: ["opencode", "anthropic", "google"] @@ -785,7 +785,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", expect(result.size).toBe(1) expect(result.has("opencode/big-pickle")).toBe(true) - expect(result.has("anthropic/claude-opus-4-6")).toBe(false) + expect(result.has("anthropic/claude-opus-4-7")).toBe(false) expect(result.has("google/gemini-3.1-pro")).toBe(false) }) @@ -812,7 +812,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", it("should handle mixed string[] and object[] formats across providers", async () => { writeProviderModelsCache({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6"], ollama: [ { id: "ministral-3:14b-32k-agent", provider: "ollama" }, { id: "qwen3-coder:32k-agent", provider: "ollama" } @@ -826,7 +826,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", }) expect(result.size).toBe(4) - expect(result.has("anthropic/claude-opus-4-6")).toBe(true) + expect(result.has("anthropic/claude-opus-4-7")).toBe(true) expect(result.has("anthropic/claude-sonnet-4-6")).toBe(true) expect(result.has("ollama/ministral-3:14b-32k-agent")).toBe(true) expect(result.has("ollama/qwen3-coder:32k-agent")).toBe(true) @@ -859,7 +859,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)", describe("isModelAvailable", () => { it("returns true when model exists via fuzzy match", () => { // given - const available = new Set(["openai/gpt-5.3-codex", "anthropic/claude-opus-4-6"]) + const available = new Set(["openai/gpt-5.3-codex", "anthropic/claude-opus-4-7"]) // when const result = isModelAvailable("gpt-5.3-codex", available) @@ -870,7 +870,7 @@ describe("isModelAvailable", () => { it("returns false when model not found", () => { // given - const available = new Set(["anthropic/claude-opus-4-6"]) + const available = new Set(["anthropic/claude-opus-4-7"]) // when const result = isModelAvailable("gpt-5.3-codex", available) @@ -924,7 +924,7 @@ describe("fallback model availability", () => { it("returns null for completely unknown model", () => { // given - const available = new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6"]) + const available = new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7"]) // when const result = fuzzyMatchModel("non-existent-model-family", available) @@ -936,7 +936,7 @@ describe("fallback model availability", () => { it("returns true when models do not match but provider is connected", () => { // given const fallbackChain = [{ providers: ["openai"], model: "gpt-5.4" }] - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) writeConnectedProvidersCache(["openai"]) // when @@ -950,10 +950,10 @@ describe("fallback model availability", () => { // given const fallbackChain = [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ] const availableModels = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "openai/gpt-5.4-preview", ]) @@ -968,7 +968,7 @@ describe("fallback model availability", () => { // given const fallbackChain = [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ] const availableModels = new Set(["google/gemini-3.1-pro"]) diff --git a/src/shared/model-availability.ts b/src/shared/model-availability.ts index 595962551..aaec07338 100644 --- a/src/shared/model-availability.ts +++ b/src/shared/model-availability.ts @@ -21,7 +21,7 @@ import { normalizeSDKResponse } from "./normalize-sdk-response" * If providers array is given, only models starting with "provider/" are considered. * * @example - * const available = new Set(["openai/gpt-5.4", "openai/gpt-5.3-codex", "anthropic/claude-opus-4-6"]) + * const available = new Set(["openai/gpt-5.4", "openai/gpt-5.3-codex", "anthropic/claude-opus-4-7"]) * fuzzyMatchModel("gpt-5.4", available) // → "openai/gpt-5.4" * fuzzyMatchModel("claude", available, ["openai"]) // → null (provider filter excludes anthropic) */ diff --git a/src/shared/model-capabilities.test.ts b/src/shared/model-capabilities.test.ts index d221633ef..e79448fbf 100644 --- a/src/shared/model-capabilities.test.ts +++ b/src/shared/model-capabilities.test.ts @@ -16,8 +16,8 @@ describe("getModelCapabilities", () => { generatedAt: "2026-03-25T00:00:00.000Z", sourceUrl: "https://models.dev/api.json", models: { - "claude-opus-4-6": { - id: "claude-opus-4-6", + "claude-opus-4-7": { + id: "claude-opus-4-7", family: "claude-opus", reasoning: true, temperature: true, @@ -66,7 +66,7 @@ describe("getModelCapabilities", () => { findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) const result = getModelCapabilities({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", runtimeModel: { variants: { low: {}, @@ -78,7 +78,7 @@ describe("getModelCapabilities", () => { }) expect(result).toMatchObject({ - canonicalModelID: "claude-opus-4-6", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", variants: ["low", "medium", "high"], supportsThinking: true, @@ -173,12 +173,12 @@ describe("getModelCapabilities", () => { findProviderModelMetadataSpy = spyOn(connectedProvidersCache, "findProviderModelMetadata").mockReturnValue(undefined) const result = getModelCapabilities({ providerID: "anthropic", - modelID: "claude-opus-4-6-thinking", + modelID: "claude-opus-4-7-thinking", bundledSnapshot, }) expect(result).toMatchObject({ - canonicalModelID: "claude-opus-4-6", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", supportsThinking: true, supportsTemperature: true, @@ -247,13 +247,13 @@ describe("getModelCapabilities", () => { test("canonicalizes provider-prefixed Claude thinking aliases to bare snapshot IDs", () => { const result = getModelCapabilities({ providerID: "anthropic", - modelID: "anthropic/claude-opus-4-6-thinking", + modelID: "anthropic/claude-opus-4-7-thinking", bundledSnapshot, }) expect(result).toMatchObject({ - requestedModelID: "anthropic/claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "anthropic/claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", family: "claude-opus", supportsThinking: true, supportsTemperature: true, diff --git a/src/shared/model-capabilities/bundled-snapshot.ts b/src/shared/model-capabilities/bundled-snapshot.ts index 65644a8cf..18ffec737 100644 --- a/src/shared/model-capabilities/bundled-snapshot.ts +++ b/src/shared/model-capabilities/bundled-snapshot.ts @@ -1,5 +1,6 @@ import bundledModelCapabilitiesSnapshotJson from "../../generated/model-capabilities.generated.json" +import { SUPPLEMENTAL_MODEL_CAPABILITIES } from "./supplemental-entries" import type { ModelCapabilitiesSnapshot } from "./types" function normalizeSnapshot( @@ -8,7 +9,15 @@ function normalizeSnapshot( return snapshot as ModelCapabilitiesSnapshot } -const bundledModelCapabilitiesSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) +const normalizedBundledSnapshot = normalizeSnapshot(bundledModelCapabilitiesSnapshotJson) + +const bundledModelCapabilitiesSnapshot: ModelCapabilitiesSnapshot = { + ...normalizedBundledSnapshot, + models: { + ...normalizedBundledSnapshot.models, + ...SUPPLEMENTAL_MODEL_CAPABILITIES, + }, +} export function getBundledModelCapabilitiesSnapshot(): ModelCapabilitiesSnapshot { return bundledModelCapabilitiesSnapshot diff --git a/src/shared/model-capabilities/supplemental-entries.ts b/src/shared/model-capabilities/supplemental-entries.ts new file mode 100644 index 000000000..87a35f71c --- /dev/null +++ b/src/shared/model-capabilities/supplemental-entries.ts @@ -0,0 +1,20 @@ +import type { ModelCapabilitiesSnapshotEntry } from "./types" + +export const SUPPLEMENTAL_MODEL_CAPABILITIES: Record = { + "gpt-5.4-mini-fast": { + id: "gpt-5.4-mini-fast", + family: "gpt-mini", + reasoning: true, + temperature: false, + toolCall: true, + modalities: { + input: ["text", "image"], + output: ["text"], + }, + limit: { + context: 400000, + input: 272000, + output: 128000, + }, + }, +} diff --git a/src/shared/model-capability-aliases.test.ts b/src/shared/model-capability-aliases.test.ts index 6d05c3abc..b6f5b6641 100644 --- a/src/shared/model-capability-aliases.test.ts +++ b/src/shared/model-capability-aliases.test.ts @@ -67,22 +67,22 @@ describe("model-capability-aliases", () => { }) test("normalizes provider-prefixed Claude thinking aliases through a pattern rule", () => { - const result = resolveModelIDAlias("anthropic/claude-opus-4-6-thinking") + const result = resolveModelIDAlias("anthropic/claude-opus-4-7-thinking") expect(result).toEqual({ - requestedModelID: "anthropic/claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "anthropic/claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", source: "pattern-alias", ruleID: "claude-thinking-legacy-alias", }) }) test("does not pattern-match nearby canonical Claude IDs incorrectly", () => { - const result = resolveModelIDAlias("claude-opus-4-6-think") + const result = resolveModelIDAlias("claude-opus-4-7-think") expect(result).toEqual({ - requestedModelID: "claude-opus-4-6-think", - canonicalModelID: "claude-opus-4-6-think", + requestedModelID: "claude-opus-4-7-think", + canonicalModelID: "claude-opus-4-7-think", source: "canonical", }) }) @@ -98,11 +98,11 @@ describe("model-capability-aliases", () => { }) test("normalizes legacy Claude thinking aliases through a pattern rule", () => { - const result = resolveModelIDAlias("claude-opus-4-6-thinking") + const result = resolveModelIDAlias("claude-opus-4-7-thinking") expect(result).toEqual({ - requestedModelID: "claude-opus-4-6-thinking", - canonicalModelID: "claude-opus-4-6", + requestedModelID: "claude-opus-4-7-thinking", + canonicalModelID: "claude-opus-4-7", source: "pattern-alias", ruleID: "claude-thinking-legacy-alias", }) diff --git a/src/shared/model-capability-aliases.ts b/src/shared/model-capability-aliases.ts index 4f9f1c752..fe7ef6b3b 100644 --- a/src/shared/model-capability-aliases.ts +++ b/src/shared/model-capability-aliases.ts @@ -41,9 +41,9 @@ const EXACT_ALIAS_RULES_BY_MODEL: ReadonlyMap = new Map( const PATTERN_ALIAS_RULES: ReadonlyArray = [ { ruleID: "claude-thinking-legacy-alias", - description: "Normalizes the legacy Claude Opus 4.6 thinking suffix to the canonical snapshot ID.", - match: (normalizedModelID) => /^claude-opus-4-6-thinking$/.test(normalizedModelID), - canonicalize: () => "claude-opus-4-6", + description: "Normalizes legacy Claude Opus thinking suffixes (4-6, 4-7) to the canonical snapshot ID.", + match: (normalizedModelID) => /^claude-opus-4-(?:6|7)-thinking$/.test(normalizedModelID), + canonicalize: () => "claude-opus-4-7", }, { ruleID: "gemini-3.1-pro-tier-alias", diff --git a/src/shared/model-capability-guardrails.test.ts b/src/shared/model-capability-guardrails.test.ts index a37534d9a..63ff3aab2 100644 --- a/src/shared/model-capability-guardrails.test.ts +++ b/src/shared/model-capability-guardrails.test.ts @@ -19,7 +19,7 @@ describe("model-capability-guardrails", () => { expect(modelIDs).toEqual([...modelIDs].sort()) expect(new Set(modelIDs).size).toBe(modelIDs.length) - expect(modelIDs).toContain("claude-opus-4-6") + expect(modelIDs).toContain("claude-opus-4-7") expect(modelIDs).toContain("gpt-5.4") expect(modelIDs).toContain("kimi-k2.5") }) diff --git a/src/shared/model-error-classifier.test.ts b/src/shared/model-error-classifier.test.ts index a1f7c5265..35c75de0a 100644 --- a/src/shared/model-error-classifier.test.ts +++ b/src/shared/model-error-classifier.test.ts @@ -31,7 +31,7 @@ describe("model-error-classifier", () => { //#given const error = { message: - "All credentials for model claude-opus-4-6-thinking are cooling down [retrying in ~5 days attempt #1]", + "All credentials for model claude-opus-4-7-thinking are cooling down [retrying in ~5 days attempt #1]", } //#when diff --git a/src/shared/model-format-normalizer.test.ts b/src/shared/model-format-normalizer.test.ts index d28ab975b..4cdca42ad 100644 --- a/src/shared/model-format-normalizer.test.ts +++ b/src/shared/model-format-normalizer.test.ts @@ -9,8 +9,8 @@ describe("normalizeModelFormat", () => { }) it("handles provider with multiple slashes", () => { - const result = normalizeModelFormat("anthropic/claude-opus-4-6/max") - expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6/max" }) + const result = normalizeModelFormat("anthropic/claude-opus-4-7/max") + expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7/max" }) }) it("returns undefined for malformed string without separator", () => { diff --git a/src/shared/model-requirements.test.ts b/src/shared/model-requirements.test.ts index 324176b57..258beb1a3 100644 --- a/src/shared/model-requirements.test.ts +++ b/src/shared/model-requirements.test.ts @@ -23,7 +23,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(primary.variant).toBe("high") }) - test("sisyphus has claude-opus-4-6 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { + test("sisyphus has claude-opus-4-7 as primary with k2p5, kimi-k2.5, gpt-5.4 medium fallbacks", () => { // #given - sisyphus agent requirement const sisyphus = AGENT_MODEL_REQUIREMENTS["sisyphus"] @@ -36,7 +36,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { const primary = sisyphus.fallbackChain[0] expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.variant).toBe("max") const second = sisyphus.fallbackChain[1] @@ -64,33 +64,38 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("big-pickle") }) - test("librarian has valid fallbackChain with opencode-go/minimax-m2.7 as primary", () => { + test("librarian has valid fallbackChain with openai/gpt-5.4-mini-fast as primary", () => { // given - librarian agent requirement const librarian = AGENT_MODEL_REQUIREMENTS["librarian"] // when - accessing librarian requirement - // then - fallbackChain exists with opencode-go/minimax-m2.7 as first entry + // then - fallbackChain exists with openai/gpt-5.4-mini-fast as first entry expect(librarian).toBeDefined() expect(librarian.fallbackChain).toBeArray() - expect(librarian.fallbackChain.length).toBeGreaterThan(0) + expect(librarian.fallbackChain).toHaveLength(5) const primary = librarian.fallbackChain[0] - expect(primary.providers[0]).toBe("opencode-go") - expect(primary.model).toBe("minimax-m2.7") + expect(primary.providers).toEqual(["openai"]) + expect(primary.model).toBe("gpt-5.4-mini-fast") const second = librarian.fallbackChain[1] - expect(second.providers[0]).toBe("opencode") + expect(second.providers[0]).toBe("opencode-go") expect(second.model).toBe("minimax-m2.7-highspeed") const tertiary = librarian.fallbackChain[2] - expect(tertiary.providers).toContain("anthropic") - expect(tertiary.model).toBe("claude-haiku-4-5") + expect(tertiary.providers[0]).toBe("opencode-go") + expect(tertiary.model).toBe("minimax-m2.7") const quaternary = librarian.fallbackChain[3] - expect(quaternary.model).toBe("gpt-5-nano") + expect(quaternary.providers).toContain("anthropic") + expect(quaternary.model).toBe("claude-haiku-4-5") + + const fifth = librarian.fallbackChain[4] + expect(fifth.providers).toContain("openai") + expect(fifth.model).toBe("gpt-5.4-nano") }) - test("explore has valid fallbackChain with grok-code-fast-1 as primary", () => { + test("explore has valid fallbackChain with openai/gpt-5.4-mini-fast as primary", () => { // given - explore agent requirement const explore = AGENT_MODEL_REQUIREMENTS["explore"] @@ -100,16 +105,15 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { 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") + expect(primary.providers).toEqual(["openai"]) + expect(primary.model).toBe("gpt-5.4-mini-fast") const secondary = explore.fallbackChain[1] expect(secondary.providers).toContain("opencode-go") expect(secondary.model).toBe("minimax-m2.7-highspeed") const tertiary = explore.fallbackChain[2] - expect(tertiary.providers).toContain("opencode") + expect(tertiary.providers).toContain("opencode-go") expect(tertiary.model).toBe("minimax-m2.7") const quaternary = explore.fallbackChain[3] @@ -117,8 +121,8 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(quaternary.model).toBe("claude-haiku-4-5") const fifth = explore.fallbackChain[4] - expect(fifth.providers).toContain("opencode") - expect(fifth.model).toBe("gpt-5-nano") + expect(fifth.providers).toContain("openai") + expect(fifth.model).toBe("gpt-5.4-nano") }) test("multimodal-looker has valid fallbackChain with gpt-5.4 as primary", () => { @@ -148,34 +152,34 @@ describe("AGENT_MODEL_REQUIREMENTS", () => { expect(last.model).toBe("gpt-5-nano") }) - test("prometheus has claude-opus-4-6 as primary", () => { + test("prometheus has claude-opus-4-7 as primary", () => { // #given - prometheus agent requirement const prometheus = AGENT_MODEL_REQUIREMENTS["prometheus"] // #when - accessing Prometheus requirement - // #then - claude-opus-4-6 is first + // #then - claude-opus-4-7 is first expect(prometheus).toBeDefined() expect(prometheus.fallbackChain).toBeArray() expect(prometheus.fallbackChain.length).toBeGreaterThan(1) const primary = prometheus.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) expect(primary.variant).toBe("max") }) - test("metis has claude-opus-4-6 as primary", () => { + test("metis has claude-opus-4-7 as primary", () => { // #given - metis agent requirement const metis = AGENT_MODEL_REQUIREMENTS["metis"] // #when - accessing Metis requirement - // #then - claude-opus-4-6 is first + // #then - claude-opus-4-7 is first expect(metis).toBeDefined() expect(metis.fallbackChain).toBeArray() expect(metis.fallbackChain.length).toBeGreaterThan(1) const primary = metis.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) expect(primary.variant).toBe("max") @@ -356,7 +360,7 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(second.model).toBe("glm-5") const third = visualEngineering.fallbackChain[2] - expect(third.model).toBe("claude-opus-4-6") + expect(third.model).toBe("claude-opus-4-7") expect(third.variant).toBe("max") const fourth = visualEngineering.fallbackChain[3] @@ -402,18 +406,18 @@ describe("CATEGORY_MODEL_REQUIREMENTS", () => { expect(primary.providers[0]).toBe("anthropic") }) - test("unspecified-high has claude-opus-4-6 as primary and gpt-5.4 as secondary", () => { + test("unspecified-high has claude-opus-4-7 as primary and gpt-5.4 as secondary", () => { // #given - unspecified-high category requirement const unspecifiedHigh = CATEGORY_MODEL_REQUIREMENTS["unspecified-high"] // #when - accessing unspecified-high requirement - // #then - claude-opus-4-6 is first and gpt-5.4 is second + // #then - claude-opus-4-7 is first and gpt-5.4 is second expect(unspecifiedHigh).toBeDefined() expect(unspecifiedHigh.fallbackChain).toBeArray() expect(unspecifiedHigh.fallbackChain.length).toBeGreaterThan(1) const primary = unspecifiedHigh.fallbackChain[0] - expect(primary.model).toBe("claude-opus-4-6") + expect(primary.model).toBe("claude-opus-4-7") expect(primary.variant).toBe("max") expect(primary.providers).toEqual(["anthropic", "github-copilot", "opencode", "vercel"]) @@ -505,14 +509,14 @@ describe("FallbackEntry type", () => { // given - a valid FallbackEntry object const entry: FallbackEntry = { providers: ["anthropic", "github-copilot", "opencode"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "high", } // when - accessing properties // then - all properties are accessible expect(entry.providers).toEqual(["anthropic", "github-copilot", "opencode"]) - expect(entry.model).toBe("claude-opus-4-6") + expect(entry.model).toBe("claude-opus-4-7") expect(entry.variant).toBe("high") }) @@ -534,7 +538,7 @@ describe("ModelRequirement type", () => { // given - a valid ModelRequirement object const requirement: ModelRequirement = { fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7", variant: "max" }, { providers: ["openai", "github-copilot"], model: "gpt-5.4", variant: "high" }, ], } @@ -543,7 +547,7 @@ describe("ModelRequirement type", () => { // then - fallbackChain is accessible with correct structure expect(requirement.fallbackChain).toBeArray() expect(requirement.fallbackChain).toHaveLength(2) - expect(requirement.fallbackChain[0].model).toBe("claude-opus-4-6") + expect(requirement.fallbackChain[0].model).toBe("claude-opus-4-7") expect(requirement.fallbackChain[1].model).toBe("gpt-5.4") }) diff --git a/src/shared/model-requirements.ts b/src/shared/model-requirements.ts index b9ac989ab..36771b4bc 100644 --- a/src/shared/model-requirements.ts +++ b/src/shared/model-requirements.ts @@ -22,7 +22,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "kimi-k2.5" }, @@ -69,7 +69,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -77,19 +77,20 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, librarian: { fallbackChain: [ + { providers: ["openai"], model: "gpt-5.4-mini-fast" }, + { providers: ["opencode-go", "vercel"], model: "minimax-m2.7-highspeed" }, { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" }, - { providers: ["opencode", "vercel"], model: "minimax-m2.7-highspeed" }, { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" }, - { providers: ["opencode", "vercel"], model: "gpt-5-nano" }, + { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }, ], }, explore: { fallbackChain: [ - { providers: ["github-copilot", "xai", "vercel"], model: "grok-code-fast-1" }, + { providers: ["openai"], model: "gpt-5.4-mini-fast" }, { providers: ["opencode-go", "vercel"], model: "minimax-m2.7-highspeed" }, - { providers: ["opencode", "vercel"], model: "minimax-m2.7" }, + { providers: ["opencode-go", "vercel"], model: "minimax-m2.7" }, { providers: ["anthropic", "opencode", "vercel"], model: "claude-haiku-4-5" }, - { providers: ["opencode", "vercel"], model: "gpt-5-nano" }, + { providers: ["openai", "opencode", "vercel"], model: "gpt-5.4-nano" }, ], }, "multimodal-looker": { @@ -104,7 +105,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -123,7 +124,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -144,7 +145,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -193,7 +194,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { { providers: ["zai-coding-plan", "opencode", "vercel"], model: "glm-5" }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -214,7 +215,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["opencode-go", "vercel"], model: "glm-5" }, @@ -229,7 +230,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { @@ -248,7 +249,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { }, { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { providers: ["openai", "github-copilot", "opencode", "vercel"], model: "gpt-5.4" }, @@ -296,7 +297,7 @@ export const CATEGORY_MODEL_REQUIREMENTS: Record = { fallbackChain: [ { providers: ["anthropic", "github-copilot", "opencode", "vercel"], - model: "claude-opus-4-6", + model: "claude-opus-4-7", variant: "max", }, { diff --git a/src/shared/model-resolver.test.ts b/src/shared/model-resolver.test.ts index 292aac718..0e546c312 100644 --- a/src/shared/model-resolver.test.ts +++ b/src/shared/model-resolver.test.ts @@ -12,7 +12,7 @@ describe("resolveModel", () => { test("returns userModel when all three are set", () => { // given const input: ModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", inheritedModel: "openai/gpt-5.4", systemDefault: "google/gemini-3.1-pro", } @@ -21,7 +21,7 @@ describe("resolveModel", () => { const result = resolveModel(input) // then - expect(result).toBe("anthropic/claude-opus-4-6") + expect(result).toBe("anthropic/claude-opus-4-7") }) test("returns inheritedModel when userModel is undefined", () => { @@ -91,7 +91,7 @@ describe("resolveModel", () => { test("same input returns same output (referential transparency)", () => { // given const input: ModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", inheritedModel: "openai/gpt-5.4", systemDefault: "google/gemini-3.1-pro", } @@ -122,11 +122,11 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "opencode/big-pickle", - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -143,8 +143,8 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "opencode/big-pickle", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -160,8 +160,8 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: " ", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -169,16 +169,16 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") - expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" }) + expect(result!.model).toBe("anthropic/claude-opus-4-7") + expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" }) }) test("empty string uiSelectedModel falls through to config override", () => { // given const input: ExtendedModelResolutionInput = { uiSelectedModel: "", - userModel: "anthropic/claude-opus-4-6", - availableModels: new Set(["anthropic/claude-opus-4-6"]), + userModel: "anthropic/claude-opus-4-7", + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -186,7 +186,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") }) }) @@ -194,11 +194,11 @@ describe("resolveModelWithFallback", () => { test("returns userModel with override source when userModel is provided", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", fallbackChain: [ - { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -206,9 +206,9 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") - expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-6" }) + expect(logSpy).toHaveBeenCalledWith("Model resolved via config override", { model: "anthropic/claude-opus-4-7" }) }) test("override takes priority even if model not in availableModels", () => { @@ -216,9 +216,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: "custom/my-model", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -235,9 +235,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: " ", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -253,9 +253,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { userModel: "", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -272,9 +272,9 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["github-copilot/claude-opus-4-6-preview", "opencode/claude-opus-4-7"]), + availableModels: new Set(["github-copilot/claude-opus-4-7-preview", "opencode/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -282,12 +282,12 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("github-copilot/claude-opus-4-6-preview") + expect(result!.model).toBe("github-copilot/claude-opus-4-7-preview") expect(result!.source).toBe("provider-fallback") expect(logSpy).toHaveBeenCalledWith("Model resolved via fallback chain (availability confirmed)", { provider: "github-copilot", - model: "claude-opus-4-6", - match: "github-copilot/claude-opus-4-6-preview", + model: "claude-opus-4-7", + match: "github-copilot/claude-opus-4-7-preview", variant: undefined, }) }) @@ -298,7 +298,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["openai", "anthropic", "google"], model: "gpt-5.4" }, ], - availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6", "google/gemini-3.1-pro"]), + availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7", "google/gemini-3.1-pro"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -334,7 +334,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic", "github-copilot"], model: "claude-opus" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6", "github-copilot/claude-opus-4-6-preview"]), + availableModels: new Set(["anthropic/claude-opus-4-7", "github-copilot/claude-opus-4-7-preview"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -342,14 +342,14 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) test("skips fallback chain when not provided", () => { // given const input: ExtendedModelResolutionInput = { - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -364,7 +364,7 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -381,7 +381,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic"], model: "CLAUDE-OPUS" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -389,7 +389,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) @@ -480,7 +480,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["anthropic"], model: "nonexistent-model" }, ], - availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["openai/gpt-5.4", "anthropic/claude-opus-4-7"]), systemDefaultModel: "google/gemini-3.1-pro", } @@ -498,7 +498,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: undefined, // no system default configured @@ -517,7 +517,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai", "google"]) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic", "openai"], model: "claude-opus-4-6" }, + { providers: ["anthropic", "openai"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", @@ -527,7 +527,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - should use connected provider (openai) from fallback chain - expect(result!.model).toBe("openai/claude-opus-4-6") + expect(result!.model).toBe("openai/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") cacheSpy.mockRestore() }) @@ -561,14 +561,14 @@ describe("resolveModelWithFallback", () => { { providers: ["openai", "opencode"], model: "claude-haiku-4-5" }, ], availableModels: new Set(), - systemDefaultModel: "anthropic/claude-opus-4-6-20251101", + systemDefaultModel: "anthropic/claude-opus-4-7-20251101", } // when const result = resolveModelWithFallback(input) // then - no provider in fallback is connected, fall through to system default - expect(result!.model).toBe("anthropic/claude-opus-4-6-20251101") + expect(result!.model).toBe("anthropic/claude-opus-4-7-20251101") expect(result!.source).toBe("system-default") cacheSpy.mockRestore() }) @@ -578,7 +578,7 @@ describe("resolveModelWithFallback", () => { const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null) const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", @@ -612,20 +612,20 @@ describe("resolveModelWithFallback", () => { describe("Multi-entry fallbackChain", () => { test("resolves to claude-opus when OpenAI unavailable but Anthropic available (oracle scenario)", () => { // given - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) // when const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "high" }, - { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-7", variant: "max" }, ], availableModels, systemDefaultModel: "system/default", }) // then - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) @@ -652,14 +652,14 @@ describe("resolveModelWithFallback", () => { // given const availableModels = new Set([ "openai/gpt-5.4", - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", ]) // when const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], availableModels, systemDefaultModel: "system/default", @@ -678,7 +678,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback({ fallbackChain: [ { providers: ["openai"], model: "gpt-5.4" }, - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, { providers: ["google"], model: "gemini-3.1-pro" }, ], availableModels, @@ -695,7 +695,7 @@ describe("resolveModelWithFallback", () => { test("result has correct ModelResolutionResult shape", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", availableModels: new Set(), systemDefaultModel: "google/gemini-3.1-pro", } @@ -718,7 +718,7 @@ describe("resolveModelWithFallback", () => { fallbackChain: [ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }, ], - availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]), systemDefaultModel: "anthropic/claude-sonnet-4-6", } @@ -754,9 +754,9 @@ describe("resolveModelWithFallback", () => { const input: ExtendedModelResolutionInput = { categoryDefaultModel: "google/gemini-3.1-pro", fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: "system/default", } @@ -764,19 +764,19 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - should fall through to fallbackChain - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) test("userModel takes priority over categoryDefaultModel", () => { // given - both userModel and categoryDefaultModel provided const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", categoryDefaultModel: "google/gemini-3.1-pro", fallbackChain: [ { providers: ["google"], model: "gemini-3.1-pro" }, ], - availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-6"]), + availableModels: new Set(["google/gemini-3.1-pro-preview", "anthropic/claude-opus-4-7"]), systemDefaultModel: "system/default", } @@ -784,7 +784,7 @@ describe("resolveModelWithFallback", () => { const result = resolveModelWithFallback(input) // then - userModel wins - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") }) @@ -916,7 +916,7 @@ describe("resolveModelWithFallback", () => { test("still returns override when userModel provided even if systemDefaultModel undefined", () => { // given const input: ExtendedModelResolutionInput = { - userModel: "anthropic/claude-opus-4-6", + userModel: "anthropic/claude-opus-4-7", availableModels: new Set(), systemDefaultModel: undefined, } @@ -926,7 +926,7 @@ describe("resolveModelWithFallback", () => { // then expect(result).toBeDefined() - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("override") }) @@ -934,9 +934,9 @@ describe("resolveModelWithFallback", () => { // given const input: ExtendedModelResolutionInput = { fallbackChain: [ - { providers: ["anthropic"], model: "claude-opus-4-6" }, + { providers: ["anthropic"], model: "claude-opus-4-7" }, ], - availableModels: new Set(["anthropic/claude-opus-4-6"]), + availableModels: new Set(["anthropic/claude-opus-4-7"]), systemDefaultModel: undefined, } @@ -945,7 +945,7 @@ describe("resolveModelWithFallback", () => { // then expect(result).toBeDefined() - expect(result!.model).toBe("anthropic/claude-opus-4-6") + expect(result!.model).toBe("anthropic/claude-opus-4-7") expect(result!.source).toBe("provider-fallback") }) }) diff --git a/src/shared/model-settings-compatibility.test.ts b/src/shared/model-settings-compatibility.test.ts index 6e7a7b590..9cf0ab172 100644 --- a/src/shared/model-settings-compatibility.test.ts +++ b/src/shared/model-settings-compatibility.test.ts @@ -6,7 +6,7 @@ describe("resolveCompatibleModelSettings", () => { test("keeps supported Claude Opus variant unchanged", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, }) @@ -20,7 +20,7 @@ describe("resolveCompatibleModelSettings", () => { test("uses model metadata first for variant support", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, capabilities: { variants: ["low", "medium", "high"] }, }) @@ -42,7 +42,7 @@ describe("resolveCompatibleModelSettings", () => { test("prefers metadata over family heuristics even when family would allow a higher level", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: { variant: "max" }, capabilities: { variants: ["low", "medium"] }, }) @@ -514,7 +514,7 @@ describe("resolveCompatibleModelSettings", () => { test("no-op when desired settings are empty", () => { const result = resolveCompatibleModelSettings({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", desired: {}, }) diff --git a/src/tools/delegate-task/model-string-parser.ts b/src/shared/model-string-parser.ts similarity index 87% rename from src/tools/delegate-task/model-string-parser.ts rename to src/shared/model-string-parser.ts index 820bb3cc3..220bbd880 100644 --- a/src/tools/delegate-task/model-string-parser.ts +++ b/src/shared/model-string-parser.ts @@ -41,13 +41,13 @@ export function parseModelString( const trimmedModel = model.trim() if (!trimmedModel) return undefined - const parts = trimmedModel.split("/") - if (parts.length < 2) { + const separatorIndex = trimmedModel.indexOf("/") + if (separatorIndex === -1) { return undefined } - const providerID = parts[0]?.trim() - const rawModelID = parts.slice(1).join("/").trim() + const providerID = trimmedModel.slice(0, separatorIndex).trim() + const rawModelID = trimmedModel.slice(separatorIndex + 1).trim() if (!providerID || !rawModelID) { return undefined } diff --git a/src/shared/opencode-provider-auth.test.ts b/src/shared/opencode-provider-auth.test.ts new file mode 100644 index 000000000..56adcc9fe --- /dev/null +++ b/src/shared/opencode-provider-auth.test.ts @@ -0,0 +1,107 @@ +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test" +import { mkdirSync, rmSync, writeFileSync } from "node:fs" +import { tmpdir } from "node:os" +import * as path from "node:path" + +import { + _resetProviderAuthCacheForTesting, + getProviderAuthType, + isProviderUsingOAuth, +} from "./opencode-provider-auth" + +describe("opencode-provider-auth", () => { + let tempDataDir: string + const originalXdgDataHome = process.env.XDG_DATA_HOME + + function writeAuthFile(contents: string): void { + const opencodeDir = path.join(tempDataDir, "opencode") + mkdirSync(opencodeDir, { recursive: true }) + writeFileSync(path.join(opencodeDir, "auth.json"), contents, "utf-8") + _resetProviderAuthCacheForTesting() + } + + beforeAll(() => { + tempDataDir = path.join(tmpdir(), `opencode-provider-auth-${Date.now()}-${Math.random().toString(36).slice(2)}`) + mkdirSync(tempDataDir, { recursive: true }) + process.env.XDG_DATA_HOME = tempDataDir + }) + + afterAll(() => { + if (originalXdgDataHome === undefined) { + delete process.env.XDG_DATA_HOME + } else { + process.env.XDG_DATA_HOME = originalXdgDataHome + } + rmSync(tempDataDir, { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + }) + + afterEach(() => { + _resetProviderAuthCacheForTesting() + }) + + it("#given auth.json with oauth entry #then detects OAuth for that provider", () => { + // given auth.json where anthropic is OAuth + writeAuthFile(JSON.stringify({ + anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 }, + opencode: { type: "api", key: "sk-x" }, + })) + + // when isProviderUsingOAuth queries each provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + const opencodeOauth = isProviderUsingOAuth("opencode") + + // then only OAuth providers return true + expect(anthropicOauth).toBe(true) + expect(opencodeOauth).toBe(false) + }) + + it("#given api-key auth.json entry #then returns the api auth type", () => { + // given auth.json with an API key for anthropic + writeAuthFile(JSON.stringify({ anthropic: { type: "api", key: "sk-ant-xxx" } })) + + // when getProviderAuthType queries the provider + const authType = getProviderAuthType("anthropic") + + // then the api type is returned + expect(authType).toBe("api") + expect(isProviderUsingOAuth("anthropic")).toBe(false) + }) + + it("#given missing auth.json #then returns undefined with no throw", () => { + // given no auth.json exists (XDG_DATA_HOME points to an empty dir) + rmSync(path.join(tempDataDir, "opencode"), { recursive: true, force: true }) + _resetProviderAuthCacheForTesting() + + // when isProviderUsingOAuth queries a provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + const anthropicType = getProviderAuthType("anthropic") + + // then callers get a safe undefined/false + expect(anthropicOauth).toBe(false) + expect(anthropicType).toBeUndefined() + }) + + it("#given malformed auth.json #then does not throw and returns undefined", () => { + // given a malformed JSON auth file + writeAuthFile("not json at all") + + // when isProviderUsingOAuth queries a provider + const anthropicOauth = isProviderUsingOAuth("anthropic") + + // then detection degrades safely + expect(anthropicOauth).toBe(false) + }) + + it("#given unknown provider #then returns undefined", () => { + // given auth.json without an entry for the queried provider + writeAuthFile(JSON.stringify({ anthropic: { type: "oauth", refresh: "r", access: "a", expires: 1 } })) + + // when querying a provider that is not present + const openai = getProviderAuthType("openai") + + // then undefined + expect(openai).toBeUndefined() + expect(isProviderUsingOAuth("openai")).toBe(false) + }) +}) diff --git a/src/shared/opencode-provider-auth.ts b/src/shared/opencode-provider-auth.ts new file mode 100644 index 000000000..235bea4c8 --- /dev/null +++ b/src/shared/opencode-provider-auth.ts @@ -0,0 +1,84 @@ +import { readFileSync, statSync } from "node:fs" +import * as path from "node:path" + +import { getDataDir } from "./data-path" +import { log } from "./logger" + +/** + * Reads OpenCode's auth.json to detect the auth type used by a provider. + * + * OpenCode stores auth credentials at `/opencode/auth.json` in the + * shape `{ [providerID]: { type: "oauth" | "api" | "wellknown", ... } }`. + * + * The file is read with mtime-based caching so we do not stat/parse it on + * every chat.params invocation. + */ + +type AuthRecord = { + type?: unknown +} + +type AuthCacheEntry = { + mtimeMs: number + map: Map +} + +let cached: AuthCacheEntry | null = null + +function getAuthFilePath(): string { + return path.join(getDataDir(), "opencode", "auth.json") +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null +} + +function loadAuthMap(): Map { + const filePath = getAuthFilePath() + + let mtimeMs: number + try { + mtimeMs = statSync(filePath).mtimeMs + } catch { + cached = null + return new Map() + } + + if (cached && cached.mtimeMs === mtimeMs) { + return cached.map + } + + try { + const raw = readFileSync(filePath, "utf-8") + const parsed: unknown = JSON.parse(raw) + const map = new Map() + if (isRecord(parsed)) { + for (const [providerID, entry] of Object.entries(parsed)) { + if (!isRecord(entry)) continue + const type = (entry as AuthRecord).type + if (typeof type === "string") { + map.set(providerID, type) + } + } + } + cached = { mtimeMs, map } + return map + } catch (error) { + log("[opencode-provider-auth] Failed to read auth.json", { + error: error instanceof Error ? error.message : String(error), + }) + return new Map() + } +} + +export function getProviderAuthType(providerID: string): string | undefined { + return loadAuthMap().get(providerID) +} + +export function isProviderUsingOAuth(providerID: string): boolean { + return getProviderAuthType(providerID) === "oauth" +} + +export function _resetProviderAuthCacheForTesting(): void { + cached = null +} diff --git a/src/shared/opencode-server-auth.ts b/src/shared/opencode-server-auth.ts index 8d4957512..02ebfa928 100644 --- a/src/shared/opencode-server-auth.ts +++ b/src/shared/opencode-server-auth.ts @@ -78,7 +78,7 @@ function tryInjectViaInterceptors(internal: UnknownRecord, auth: string): boolea return false } - use((request: Request): Request => { + use.call(requestInterceptors, (request: Request): Request => { if (!request.headers.get("Authorization")) { request.headers.set("Authorization", auth) } diff --git a/src/shared/permission-compat.ts b/src/shared/permission-compat.ts index fd8253b77..d6df20aed 100644 --- a/src/shared/permission-compat.ts +++ b/src/shared/permission-compat.ts @@ -13,12 +13,14 @@ export interface PermissionFormat { * Creates tool restrictions that deny specified tools. */ export function createAgentToolRestrictions( - denyTools: string[] + denyTools: string[], + allowTools: string[] = [], ): PermissionFormat { return { - permission: Object.fromEntries( - denyTools.map((tool) => [tool, "deny" as const]) - ), + permission: Object.fromEntries([ + ...denyTools.map((tool) => [tool, "deny" as const]), + ...allowTools.map((tool) => [tool, "allow" as const]), + ]), } } diff --git a/src/shared/project-discovery-dirs.test.ts b/src/shared/project-discovery-dirs.test.ts index 39ba5dc13..d2904bc72 100644 --- a/src/shared/project-discovery-dirs.test.ts +++ b/src/shared/project-discovery-dirs.test.ts @@ -1,15 +1,10 @@ -import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import { afterEach, beforeEach, describe, expect, it, mock } 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()}`) +let worktreeSpawnCount = 0 function canonicalPath(path: string): string { return realpathSync(path) @@ -24,7 +19,35 @@ describe("project-discovery-dirs", () => { 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", () => { + it("#given repeated worktree detection #when detecting twice #then reuses the cached result", async () => { + // given + worktreeSpawnCount = 0 + + mock.module("node:child_process", () => ({ + execFileSync: () => { + worktreeSpawnCount += 1 + return TEST_DIR + }, + })) + + const { clearWorktreeCache, detectWorktreePath } = await import("./project-discovery-dirs") + + clearWorktreeCache() + + // when + const firstPath = detectWorktreePath("/some/dir") + const secondPath = detectWorktreePath("/some/dir") + clearWorktreeCache() + const thirdPath = detectWorktreePath("/some/dir") + + // then + expect(firstPath).toBe(TEST_DIR) + expect(secondPath).toBe(TEST_DIR) + expect(thirdPath).toBe(TEST_DIR) + expect(worktreeSpawnCount).toBe(2) + }) + + it("#given nested .opencode skill directories #when finding project opencode skill dirs #then returns nearest-first with aliases", async () => { // given const projectDir = join(TEST_DIR, "project") const childDir = join(projectDir, "apps", "cli") @@ -32,6 +55,8 @@ describe("project-discovery-dirs", () => { mkdirSync(join(projectDir, ".opencode", "skills"), { recursive: true }) mkdirSync(join(TEST_DIR, ".opencode", "skills"), { recursive: true }) + const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs") + // when const directories = findProjectOpencodeSkillDirs(childDir) @@ -43,13 +68,15 @@ describe("project-discovery-dirs", () => { ]) }) - it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", () => { + it("#given nested .opencode command directories #when finding project opencode command dirs #then returns nearest-first with aliases", async () => { // 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 }) + const { findProjectOpencodeCommandDirs } = await import("./project-discovery-dirs") + // when const directories = findProjectOpencodeCommandDirs(childDir) @@ -60,13 +87,15 @@ describe("project-discovery-dirs", () => { ]) }) - it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", () => { + it("#given ancestor claude and agents skill directories #when finding project compatibility dirs #then discovers both scopes", async () => { // 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 }) + const { findProjectAgentsSkillDirs, findProjectClaudeSkillDirs } = await import("./project-discovery-dirs") + // when const claudeDirectories = findProjectClaudeSkillDirs(childDir) const agentsDirectories = findProjectAgentsSkillDirs(childDir) @@ -76,17 +105,20 @@ describe("project-discovery-dirs", () => { 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", () => { + it("#given a stop directory #when finding ancestor dirs #then it does not scan beyond the stop boundary", async () => { // 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 }) + const { findProjectOpencodeSkillDirs } = await import("./project-discovery-dirs") + // 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 index 4e22b66f6..5e243df5a 100644 --- a/src/shared/project-discovery-dirs.ts +++ b/src/shared/project-discovery-dirs.ts @@ -2,6 +2,8 @@ import { execFileSync } from "node:child_process" import { existsSync, realpathSync } from "node:fs" import { dirname, join, resolve } from "node:path" +const worktreePathCache = new Map() + function normalizePath(path: string): string { const resolvedPath = resolve(path) if (!existsSync(resolvedPath)) { @@ -49,15 +51,28 @@ function findAncestorDirectories( } } -function detectWorktreePath(directory: string): string | undefined { +export function clearWorktreeCache(): void { + worktreePathCache.clear() +} + +export function detectWorktreePath(directory: string): string | undefined { + const resolvedDirectory = resolve(directory) + if (worktreePathCache.has(resolvedDirectory)) { + return worktreePathCache.get(resolvedDirectory) + } + try { - return execFileSync("git", ["rev-parse", "--show-toplevel"], { - cwd: directory, + const worktreePath = execFileSync("git", ["rev-parse", "--show-toplevel"], { + cwd: resolvedDirectory, encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"], }).trim() + + worktreePathCache.set(resolvedDirectory, worktreePath) + return worktreePath } catch { + worktreePathCache.set(resolvedDirectory, undefined) return undefined } } diff --git a/src/shared/provider-model-id-transform.ts b/src/shared/provider-model-id-transform.ts index c01942a0f..59904199d 100644 --- a/src/shared/provider-model-id-transform.ts +++ b/src/shared/provider-model-id-transform.ts @@ -23,9 +23,9 @@ function applyGatewayTransforms(model: string): string { } export function transformModelForProvider(provider: string, model: string): string { - // Vercel AI Gateway expects / (e.g. anthropic/claude-opus-4.6). - // Canonical names in model-requirements.ts may be bare (claude-opus-4-6) or - // already prefixed (anthropic/claude-opus-4-6). Both need gateway-specific transforms. + // Vercel AI Gateway expects / (e.g. anthropic/claude-opus-4.7). + // Canonical names in model-requirements.ts may be bare (claude-opus-4-7) or + // already prefixed (anthropic/claude-opus-4-7). Both need gateway-specific transforms. if (provider === "vercel") { // Already prefixed — transform only the model part const slashIndex = model.indexOf("/") diff --git a/src/shared/ripgrep-cli.ts b/src/shared/ripgrep-cli.ts new file mode 100644 index 000000000..5f62b3ad7 --- /dev/null +++ b/src/shared/ripgrep-cli.ts @@ -0,0 +1,114 @@ +import { spawnSync } from "node:child_process" +import { existsSync } from "node:fs" +import { dirname, join } from "node:path" +import { downloadAndInstallRipgrep, getInstalledRipgrepPath } from "../tools/grep/downloader" +import { getDataDir } from "./data-path" +import { log } from "./logger" +import { PUBLISHED_PACKAGE_NAME } from "./plugin-identity" + +export type GrepBackend = "rg" | "grep" + +export interface ResolvedCli { + path: string + backend: GrepBackend +} + +export const DEFAULT_RG_THREADS = 4 + +let cachedCli: ResolvedCli | null = null +let autoInstallAttempted = false + +function findExecutable(name: string): string | null { + const isWindows = process.platform === "win32" + const cmd = isWindows ? "where" : "which" + + try { + const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 }) + if (result.status === 0 && result.stdout.trim()) { + return result.stdout.trim().split("\n")[0] + } + } catch { + return null + } + return null +} + +function getOpenCodeBundledRg(): string | null { + const execPath = process.execPath + const execDir = dirname(execPath) + + const isWindows = process.platform === "win32" + const rgName = isWindows ? "rg.exe" : "rg" + + const candidates = [ + join(getDataDir(), "opencode", "bin", rgName), + join(execDir, rgName), + join(execDir, "bin", rgName), + join(execDir, "..", "bin", rgName), + join(execDir, "..", "libexec", rgName), + ] + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate + } + } + + return null +} + +export function resolveGrepCli(): ResolvedCli { + if (cachedCli) { + return cachedCli + } + + const rgPath = getOpenCodeBundledRg() ?? findExecutable("rg") ?? getInstalledRipgrepPath() + if (rgPath) { + cachedCli = { path: rgPath, backend: "rg" } + return cachedCli + } + + const grep = findExecutable("grep") + if (grep) { + cachedCli = { path: grep, backend: "grep" } + return cachedCli + } + + cachedCli = { path: "rg", backend: "rg" } + return cachedCli +} + +export async function resolveGrepCliWithAutoInstall(): Promise { + const current = resolveGrepCli() + + if (current.backend === "rg" && current.path !== "rg") { + return current + } + + if (autoInstallAttempted) { + return current + } + + autoInstallAttempted = true + + try { + const rgPath = await downloadAndInstallRipgrep() + cachedCli = { path: rgPath, backend: "rg" } + return cachedCli + } catch (error) { + const message = error instanceof Error ? error.message : String(error) + + if (current.backend === "grep") { + log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, { + error: message, + grep_path: current.path, + }) + } else { + log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, { + error: message, + }) + } + + return current + } +} diff --git a/src/shared/tmux/tmux-utils.ts b/src/shared/tmux/tmux-utils.ts index a9aab095a..6ccdeed31 100644 --- a/src/shared/tmux/tmux-utils.ts +++ b/src/shared/tmux/tmux-utils.ts @@ -10,6 +10,8 @@ export { spawnTmuxPane } from "./tmux-utils/pane-spawn" export { closeTmuxPane } from "./tmux-utils/pane-close" export { replaceTmuxPane } from "./tmux-utils/pane-replace" export { spawnTmuxWindow } from "./tmux-utils/window-spawn" -export { spawnTmuxSession } from "./tmux-utils/session-spawn" +export { spawnTmuxSession, getIsolatedSessionName } from "./tmux-utils/session-spawn" +export { killTmuxSessionIfExists } from "./tmux-utils/session-kill" +export { sweepStaleOmoAgentSessions } from "./tmux-utils/stale-session-sweep" export { applyLayout, enforceMainPaneWidth } from "./tmux-utils/layout" diff --git a/src/shared/tmux/tmux-utils/index.ts b/src/shared/tmux/tmux-utils/index.ts new file mode 100644 index 000000000..e55436a1c --- /dev/null +++ b/src/shared/tmux/tmux-utils/index.ts @@ -0,0 +1 @@ +export { killTmuxSessionIfExists } from "./session-kill" diff --git a/src/shared/tmux/tmux-utils/pane-close.test.ts b/src/shared/tmux/tmux-utils/pane-close.test.ts new file mode 100644 index 000000000..b8d5d7887 --- /dev/null +++ b/src/shared/tmux/tmux-utils/pane-close.test.ts @@ -0,0 +1,221 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" + +type CloseTmuxPane = typeof import("./pane-close").closeTmuxPane + +type SpawnCall = { + command: string[] + options: { + stdout?: string + stderr?: string + } +} + +type FakeSubprocess = { + exited: Promise + stdout: ReadableStream + stderr: ReadableStream +} + +const TIMEOUT = Symbol("timeout") +const spawnCalls: SpawnCall[] = [] +const queuedProcesses: FakeSubprocess[] = [] + +function createClosedStream(): ReadableStream { + return new ReadableStream({ + start(controller) { + controller.close() + }, + }) +} + +type DrainSignal = { onPull: () => void } + +function createDrainSensitiveStream(byteLength: number, signal: DrainSignal): ReadableStream { + let remainingBytes = byteLength + const chunk = new TextEncoder().encode("x".repeat(16 * 1024)) + + return new ReadableStream({ + pull(controller) { + signal.onPull() + + if (remainingBytes <= 0) { + controller.close() + return + } + + const nextChunkSize = Math.min(remainingBytes, chunk.byteLength) + controller.enqueue(chunk.subarray(0, nextChunkSize)) + remainingBytes -= nextChunkSize + }, + }) +} + +function createProcess(exitCode: number): FakeSubprocess { + return { + exited: Promise.resolve(exitCode), + stdout: createClosedStream(), + stderr: createClosedStream(), + } +} + +function createStdoutSensitiveProcess(exitCode: number, stdoutBytes: number): FakeSubprocess { + let resolveDrained: () => void = () => undefined + const drained = new Promise((resolve) => { + resolveDrained = resolve + }) + const stdout = createDrainSensitiveStream(stdoutBytes, { onPull: () => resolveDrained() }) + + return { + exited: drained.then(() => exitCode), + stdout, + stderr: createClosedStream(), + } +} + +const spawnMock = mock((command: string[], options: { stdout?: string; stderr?: string } = {}): FakeSubprocess => { + spawnCalls.push({ command, options }) + + const process = queuedProcesses.shift() + if (!process) { + throw new Error(`No fake subprocess configured for ${command.join(" ")}`) + } + + return process +}) + +const isInsideTmuxMock = mock((): boolean => true) +const getTmuxPathMock = mock(async (): Promise => "tmux") +const logMock = mock(() => undefined) + +const paneCloseSpecifier = import.meta.resolve("./pane-close") +const environmentSpecifier = import.meta.resolve("./environment") +const loggerSpecifier = import.meta.resolve("../../logger") +const spawnProcessSpecifier = import.meta.resolve("./spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") + +async function loadCloseTmuxPane(): Promise { + const module = await import(`${paneCloseSpecifier}?test=${crypto.randomUUID()}`) + return module.closeTmuxPane +} + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) + mock.module(loggerSpecifier, () => ({ log: logMock })) +} + +function resolveWithin(promise: Promise, milliseconds: number): Promise { + return Promise.race([ + promise, + new Promise((resolve) => { + setTimeout(() => resolve(TIMEOUT), milliseconds) + }), + ]) +} + +describe("closeTmuxPane", () => { + beforeEach(() => { + registerModuleMocks() + spawnCalls.length = 0 + queuedProcesses.length = 0 + spawnMock.mockClear() + isInsideTmuxMock.mockClear() + getTmuxPathMock.mockClear() + logMock.mockClear() + + isInsideTmuxMock.mockImplementation((): boolean => true) + getTmuxPathMock.mockImplementation(async (): Promise => "tmux") + }) + + it("#given pane exists #when closeTmuxPane called #then returns true and invokes send-keys + kill-pane in order", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createProcess(0)) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(true) + expect(spawnCalls).toEqual([ + { command: ["tmux", "send-keys", "-t", "%42", "C-c"], options: { stdout: "ignore", stderr: "ignore" } }, + { command: ["tmux", "kill-pane", "-t", "%42"], options: { stdout: "pipe", stderr: "pipe" } }, + ]) + }) + + it("#given not inside tmux #when closeTmuxPane called #then returns false without spawn", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + isInsideTmuxMock.mockImplementation((): boolean => false) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given tmux not found #when closeTmuxPane called #then returns false without spawn", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + getTmuxPathMock.mockImplementation(async (): Promise => undefined) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given kill-pane fails with unknown error #when closeTmuxPane called #then returns false", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createProcess(1)) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(false) + }) + + it("#given pane already closed by Ctrl+C (kill-pane reports 'can't find pane') #when closeTmuxPane called #then returns true", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push( + createProcess(0), + { + exited: Promise.resolve(1), + stdout: createClosedStream(), + stderr: new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode("can't find pane: %42\n")) + controller.close() + }, + }), + }, + ) + + // when + const result = await closeTmuxPane("%42") + + // then + expect(result).toBe(true) + }) + + it("#given kill-pane stdout stream waits for drain #when closeTmuxPane called #then returns true once drainer consumes stdout", async () => { + // given + const closeTmuxPane = await loadCloseTmuxPane() + queuedProcesses.push(createProcess(0), createStdoutSensitiveProcess(0, 16 * 1024)) + + // when + const result = await resolveWithin(closeTmuxPane("%42"), 2000) + + // then + expect(result).not.toBe(TIMEOUT) + expect(result).toBe(true) + }) +}) diff --git a/src/shared/tmux/tmux-utils/pane-close.ts b/src/shared/tmux/tmux-utils/pane-close.ts index cc6f4b6c4..e62e46296 100644 --- a/src/shared/tmux/tmux-utils/pane-close.ts +++ b/src/shared/tmux/tmux-utils/pane-close.ts @@ -1,13 +1,18 @@ -import { spawn } from "bun" -import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver" -import { isInsideTmux } from "./environment" - function delay(milliseconds: number): Promise { return new Promise((resolve) => setTimeout(resolve, milliseconds)) } +async function readStream(stream: ReadableStream | null | undefined): Promise { + return stream ? new Response(stream).text() : "" +} + export async function closeTmuxPane(paneId: string): Promise { - const { log } = await import("../../logger") + const [{ log }, { isInsideTmux }, { getTmuxPath }, { spawn }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./spawn-process"), + ]) if (!isInsideTmux()) { log("[closeTmuxPane] SKIP: not inside tmux") @@ -22,8 +27,8 @@ export async function closeTmuxPane(paneId: string): Promise { log("[closeTmuxPane] sending Ctrl+C for graceful shutdown", { paneId }) const ctrlCProc = spawn([tmux, "send-keys", "-t", paneId, "C-c"], { - stdout: "pipe", - stderr: "pipe", + stdout: "ignore", + stderr: "ignore", }) await ctrlCProc.exited @@ -31,18 +36,29 @@ export async function closeTmuxPane(paneId: string): Promise { log("[closeTmuxPane] killing pane", { paneId }) - const proc = spawn([tmux, "kill-pane", "-t", paneId], { + const killPaneProc = spawn([tmux, "kill-pane", "-t", paneId], { stdout: "pipe", stderr: "pipe", }) - const exitCode = await proc.exited - const stderr = await new Response(proc.stderr).text() + const [, stderr, exitCode] = await Promise.all([ + readStream(killPaneProc.stdout), + readStream(killPaneProc.stderr), + killPaneProc.exited, + ]) - if (exitCode !== 0) { - log("[closeTmuxPane] FAILED", { paneId, exitCode, stderr: stderr.trim() }) - } else { - log("[closeTmuxPane] SUCCESS", { paneId }) + const trimmedStderr = stderr.trim() + const paneAlreadyGone = exitCode !== 0 && /can't find pane/i.test(trimmedStderr) + + if (paneAlreadyGone) { + log("[closeTmuxPane] SUCCESS (pane already closed by Ctrl+C)", { paneId }) + return true } - return exitCode === 0 + if (exitCode !== 0) { + log("[closeTmuxPane] FAILED", { paneId, exitCode, stderr: trimmedStderr }) + return false + } + + log("[closeTmuxPane] SUCCESS", { paneId }) + return true } diff --git a/src/shared/tmux/tmux-utils/session-kill.test.ts b/src/shared/tmux/tmux-utils/session-kill.test.ts new file mode 100644 index 000000000..ca185d980 --- /dev/null +++ b/src/shared/tmux/tmux-utils/session-kill.test.ts @@ -0,0 +1,173 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" + +type KillTmuxSessionIfExists = typeof import("./session-kill").killTmuxSessionIfExists + +type SpawnCall = { + command: string[] + options: { + stdout?: string + stderr?: string + } +} + +type FakeSubprocess = { + exited: Promise + stdout: ReadableStream + stderr: ReadableStream +} + +const spawnCalls: SpawnCall[] = [] +const queuedProcesses: FakeSubprocess[] = [] + +function createStream(chunks: string[] = []): ReadableStream { + const textEncoder = new TextEncoder() + + return new ReadableStream({ + start(controller) { + for (const chunk of chunks) { + controller.enqueue(textEncoder.encode(chunk)) + } + + controller.close() + }, + }) +} + +function createProcess(exitCode: number, output: { stdout?: string[]; stderr?: string[] } = {}): FakeSubprocess { + return { + exited: Promise.resolve(exitCode), + stdout: createStream(output.stdout), + stderr: createStream(output.stderr), + } +} + +const spawnMock = mock((command: string[], options: { stdout?: string; stderr?: string } = {}) => { + spawnCalls.push({ command, options }) + + const process = queuedProcesses.shift() + if (!process) { + throw new Error(`No fake subprocess configured for ${command.join(" ")}`) + } + + return process +}) + +const isInsideTmuxMock = mock((): boolean => true) +const getTmuxPathMock = mock(async (): Promise => "tmux") +const logMock = mock(() => undefined) + +const sessionKillSpecifier = import.meta.resolve("./session-kill") +const environmentSpecifier = import.meta.resolve("./environment") +const loggerSpecifier = import.meta.resolve("../../logger") +const spawnProcessSpecifier = import.meta.resolve("./spawn-process") +const tmuxPathResolverSpecifier = import.meta.resolve("../../../tools/interactive-bash/tmux-path-resolver") + +async function loadKillTmuxSessionIfExists(): Promise { + const module = await import(`${sessionKillSpecifier}?test=${crypto.randomUUID()}`) + return module.killTmuxSessionIfExists +} + +function registerModuleMocks(): void { + mock.module(spawnProcessSpecifier, () => ({ spawn: spawnMock })) + mock.module(environmentSpecifier, () => ({ isInsideTmux: isInsideTmuxMock })) + mock.module(tmuxPathResolverSpecifier, () => ({ getTmuxPath: getTmuxPathMock })) + mock.module(loggerSpecifier, () => ({ log: logMock })) +} + +describe("killTmuxSessionIfExists", () => { + beforeEach(() => { + registerModuleMocks() + spawnCalls.length = 0 + queuedProcesses.length = 0 + spawnMock.mockClear() + isInsideTmuxMock.mockClear() + getTmuxPathMock.mockClear() + logMock.mockClear() + + isInsideTmuxMock.mockImplementation((): boolean => true) + getTmuxPathMock.mockImplementation(async (): Promise => "tmux") + }) + + it("#given omo-agents session exists #when killTmuxSessionIfExists called #then kill-session invoked and returns true", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push(createProcess(0), createProcess(0, { stdout: ["killed"], stderr: [] })) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(true) + expect(spawnCalls).toEqual([ + { + command: ["tmux", "has-session", "-t", "omo-agents"], + options: { stdout: "ignore", stderr: "ignore" }, + }, + { + command: ["tmux", "kill-session", "-t", "omo-agents"], + options: { stdout: "pipe", stderr: "pipe" }, + }, + ]) + }) + + it("#given omo-agents session does NOT exist (has-session exits non-zero) #when killTmuxSessionIfExists called #then NO kill-session invocation and returns false", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push(createProcess(1)) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toEqual([ + { + command: ["tmux", "has-session", "-t", "omo-agents"], + options: { stdout: "ignore", stderr: "ignore" }, + }, + ]) + }) + + it("#given not inside tmux #when killTmuxSessionIfExists called #then returns false without any spawn", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + isInsideTmuxMock.mockReturnValue(false) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + expect(getTmuxPathMock).toHaveBeenCalledTimes(0) + }) + + it("#given tmux not found #when killTmuxSessionIfExists called #then returns false without spawn", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + getTmuxPathMock.mockResolvedValue(undefined) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(0) + }) + + it("#given kill-session itself fails (e.g., race between has-session and kill) #when killTmuxSessionIfExists called #then returns false but does not throw", async () => { + // given + const killTmuxSessionIfExists = await loadKillTmuxSessionIfExists() + queuedProcesses.push( + createProcess(0), + createProcess(1, { stdout: [], stderr: ["no session"] }), + ) + + // when + const result = await killTmuxSessionIfExists("omo-agents") + + // then + expect(result).toBe(false) + expect(spawnCalls).toHaveLength(2) + }) +}) diff --git a/src/shared/tmux/tmux-utils/session-kill.ts b/src/shared/tmux/tmux-utils/session-kill.ts new file mode 100644 index 000000000..fc5f765df --- /dev/null +++ b/src/shared/tmux/tmux-utils/session-kill.ts @@ -0,0 +1,51 @@ +async function readStream(stream: ReadableStream | null | undefined): Promise { + return stream ? new Response(stream).text() : "" +} + +export async function killTmuxSessionIfExists(sessionName: string): Promise { + const [{ log }, { isInsideTmux }, { getTmuxPath }, { spawn }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./spawn-process"), + ]) + + if (!isInsideTmux()) { + log("[killTmuxSessionIfExists] SKIP: not inside tmux", { sessionName }) + return false + } + + const tmux = await getTmuxPath() + if (!tmux) { + log("[killTmuxSessionIfExists] SKIP: tmux not found", { sessionName }) + return false + } + + const hasSessionProcess = spawn([tmux, "has-session", "-t", sessionName], { + stdout: "ignore", + stderr: "ignore", + }) + + if ((await hasSessionProcess.exited) !== 0) { + log("[killTmuxSessionIfExists] SKIP: session not found", { sessionName }) + return false + } + + const killSessionProcess = spawn([tmux, "kill-session", "-t", sessionName], { + stdout: "pipe", + stderr: "pipe", + }) + const [, stderr, exitCode] = await Promise.all([ + readStream(killSessionProcess.stdout), + readStream(killSessionProcess.stderr), + killSessionProcess.exited, + ]) + + if (exitCode !== 0) { + log("[killTmuxSessionIfExists] FAILED", { sessionName, exitCode, stderr: stderr.trim() }) + return false + } + + log("[killTmuxSessionIfExists] SUCCESS", { sessionName }) + return true +} diff --git a/src/shared/tmux/tmux-utils/session-spawn.ts b/src/shared/tmux/tmux-utils/session-spawn.ts index db1feee29..a6fd15d2d 100644 --- a/src/shared/tmux/tmux-utils/session-spawn.ts +++ b/src/shared/tmux/tmux-utils/session-spawn.ts @@ -6,7 +6,11 @@ import { isInsideTmux } from "./environment" import { isServerRunning } from "./server-health" import { shellEscapeForDoubleQuotedCommand } from "../../shell-env" -const ISOLATED_SESSION_NAME = "omo-agents" +const ISOLATED_SESSION_NAME_PREFIX = "omo-agents" + +export function getIsolatedSessionName(pid: number = process.pid): string { + return `${ISOLATED_SESSION_NAME_PREFIX}-${pid}` +} async function getWindowDimensions( tmux: string, @@ -87,12 +91,13 @@ export async function spawnTmuxSession( } } - const sessionAlreadyExists = await sessionExists(tmux, ISOLATED_SESSION_NAME) + const isolatedSessionName = getIsolatedSessionName() + const sessionAlreadyExists = await sessionExists(tmux, isolatedSessionName) const args = sessionAlreadyExists ? [ "new-window", - "-t", ISOLATED_SESSION_NAME, + "-t", isolatedSessionName, "-P", "-F", "#{pane_id}", opencodeCmd, @@ -100,7 +105,7 @@ export async function spawnTmuxSession( : [ "new-session", "-d", - "-s", ISOLATED_SESSION_NAME, + "-s", isolatedSessionName, ...sizeArgs, "-P", "-F", "#{pane_id}", @@ -109,7 +114,7 @@ export async function spawnTmuxSession( log("[spawnTmuxSession] spawning", { mode: sessionAlreadyExists ? "new-window" : "new-session", - sessionName: ISOLATED_SESSION_NAME, + sessionName: isolatedSessionName, }) const proc = spawn([tmux, ...args], { stdout: "pipe", stderr: "pipe" }) @@ -140,6 +145,6 @@ export async function spawnTmuxSession( }) } - log("[spawnTmuxSession] SUCCESS", { paneId, sessionName: ISOLATED_SESSION_NAME }) + log("[spawnTmuxSession] SUCCESS", { paneId, sessionName: isolatedSessionName }) return { success: true, paneId } } diff --git a/src/shared/tmux/tmux-utils/spawn-process.ts b/src/shared/tmux/tmux-utils/spawn-process.ts new file mode 100644 index 000000000..c75826cab --- /dev/null +++ b/src/shared/tmux/tmux-utils/spawn-process.ts @@ -0,0 +1 @@ +export { spawn } from "bun" diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts new file mode 100644 index 000000000..1acc171ed --- /dev/null +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.test.ts @@ -0,0 +1,154 @@ +import { beforeEach, describe, expect, it, mock } from "bun:test" +import { sweepStaleOmoAgentSessionsWith, type SweepDeps } from "./stale-session-sweep" + +type SweepFixture = { + deps: SweepDeps + candidates: string[] + killed: string[] + killSessionMock: ReturnType + setCandidates: (sessions: string[]) => void + setAlive: (predicate: (pid: number) => boolean) => void +} + +function createFixture(): SweepFixture { + const candidates: string[] = [] + const killed: string[] = [] + let aliveCheck: (pid: number) => boolean = () => false + + const killSessionMock = mock(async (sessionName: string): Promise => { + killed.push(sessionName) + return true + }) + + const deps: SweepDeps = { + isInsideTmux: () => true, + getTmuxPath: async () => "tmux", + listCandidateSessions: async () => [...candidates], + killSession: killSessionMock, + processAlive: (pid) => aliveCheck(pid), + currentPid: 12345, + log: () => undefined, + } + + return { + deps, + candidates, + killed, + killSessionMock, + setCandidates: (sessions) => { + candidates.length = 0 + candidates.push(...sessions) + }, + setAlive: (predicate) => { + aliveCheck = predicate + }, + } +} + +describe("sweepStaleOmoAgentSessionsWith", () => { + let fixture: SweepFixture + + beforeEach(() => { + fixture = createFixture() + }) + + it("#given not inside tmux #when sweep called #then returns 0 without listing", async () => { + // given + const deps: SweepDeps = { ...fixture.deps, isInsideTmux: () => false } + + // when + const result = await sweepStaleOmoAgentSessionsWith(deps) + + // then + expect(result).toBe(0) + }) + + it("#given tmux not found #when sweep called #then returns 0 without listing", async () => { + // given + const deps: SweepDeps = { ...fixture.deps, getTmuxPath: async () => undefined } + + // when + const result = await sweepStaleOmoAgentSessionsWith(deps) + + // then + expect(result).toBe(0) + }) + + it("#given candidate list is empty #when sweep called #then returns 0 and does not kill anything", async () => { + // given + fixture.setCandidates([]) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(0) + expect(fixture.killed).toEqual([]) + }) + + it("#given sessions with dead PIDs #when sweep called #then each dead session is killed once", async () => { + // given + fixture.setCandidates(["omo-agents-99991", "omo-agents-99992"]) + fixture.setAlive(() => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(2) + expect(fixture.killed).toEqual(["omo-agents-99991", "omo-agents-99992"]) + }) + + it("#given session matches current PID #when sweep called #then it is NOT killed", async () => { + // given + fixture.setCandidates([`omo-agents-${fixture.deps.currentPid}`, "omo-agents-99999"]) + fixture.setAlive(() => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(1) + expect(fixture.killed).toEqual(["omo-agents-99999"]) + }) + + it("#given session PID is still alive #when sweep called #then it is NOT killed", async () => { + // given + fixture.setCandidates(["omo-agents-88888"]) + fixture.setAlive((pid) => pid === 88888) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(0) + expect(fixture.killed).toEqual([]) + }) + + it("#given killSession returns false #when sweep called #then session is not counted toward killedCount", async () => { + // given + fixture.setCandidates(["omo-agents-55555"]) + fixture.setAlive(() => false) + fixture.killSessionMock.mockImplementation(async () => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(0) + expect(fixture.killSessionMock).toHaveBeenCalledTimes(1) + }) + + it("#given non-matching sessions mixed in #when sweep called #then only omo-agents- sessions are considered", async () => { + // given + fixture.setCandidates(["main", "omo-agents-99999", "other-session", "omo-agents-abc"]) + fixture.setAlive(() => false) + + // when + const result = await sweepStaleOmoAgentSessionsWith(fixture.deps) + + // then + expect(result).toBe(1) + expect(fixture.killed).toEqual(["omo-agents-99999"]) + }) +}) diff --git a/src/shared/tmux/tmux-utils/stale-session-sweep.ts b/src/shared/tmux/tmux-utils/stale-session-sweep.ts new file mode 100644 index 000000000..c8b27e938 --- /dev/null +++ b/src/shared/tmux/tmux-utils/stale-session-sweep.ts @@ -0,0 +1,99 @@ +const STALE_SESSION_PATTERN = /^omo-agents-(\d+)$/ + +function isProcessAlive(pid: number): boolean { + try { + process.kill(pid, 0) + return true + } catch (error) { + const err = error as NodeJS.ErrnoException + return err?.code === "EPERM" + } +} + +async function listOmoAgentSessionsViaTmux(tmux: string): Promise { + const { spawn } = await import("./spawn-process") + const proc = spawn([tmux, "list-sessions", "-F", "#{session_name}"], { + stdout: "pipe", + stderr: "pipe", + }) + const [stdout, , exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]) + + if (exitCode !== 0) { + return [] + } + + return stdout + .split("\n") + .map((line) => line.trim()) + .filter((name) => STALE_SESSION_PATTERN.test(name)) +} + +export type SweepDeps = { + isInsideTmux: () => boolean + getTmuxPath: () => Promise + listCandidateSessions: (tmux: string) => Promise + killSession: (sessionName: string) => Promise + processAlive: (pid: number) => boolean + currentPid: number + log: (message: string, payload?: unknown) => void +} + +async function buildRuntimeDeps(): Promise { + const [{ log }, { isInsideTmux }, { getTmuxPath }, { killTmuxSessionIfExists }] = await Promise.all([ + import("../../logger"), + import("./environment"), + import("../../../tools/interactive-bash/tmux-path-resolver"), + import("./session-kill"), + ]) + + return { + isInsideTmux, + getTmuxPath, + listCandidateSessions: listOmoAgentSessionsViaTmux, + killSession: killTmuxSessionIfExists, + processAlive: isProcessAlive, + currentPid: process.pid, + log, + } +} + +export async function sweepStaleOmoAgentSessionsWith(deps: SweepDeps): Promise { + if (!deps.isInsideTmux()) { + return 0 + } + + const tmux = await deps.getTmuxPath() + if (!tmux) { + return 0 + } + + const candidateSessions = await deps.listCandidateSessions(tmux) + let killedCount = 0 + + for (const sessionName of candidateSessions) { + const pidMatch = sessionName.match(STALE_SESSION_PATTERN) + if (!pidMatch) continue + + const pid = Number.parseInt(pidMatch[1], 10) + if (!Number.isFinite(pid)) continue + if (pid === deps.currentPid) continue + if (deps.processAlive(pid)) continue + + deps.log("[sweepStaleOmoAgentSessions] killing stale session", { sessionName, deadPid: pid }) + const killed = await deps.killSession(sessionName) + if (killed) { + killedCount += 1 + } + } + + return killedCount +} + +export async function sweepStaleOmoAgentSessions(): Promise { + const deps = await buildRuntimeDeps() + return sweepStaleOmoAgentSessionsWith(deps) +} diff --git a/src/tools/AGENTS.md b/src/tools/AGENTS.md index 6c69183cf..d6e6f41ad 100644 --- a/src/tools/AGENTS.md +++ b/src/tools/AGENTS.md @@ -1,6 +1,6 @@ # src/tools/ - 26 Tools Across 16 Directories -**Generated:** 2026-04-11 +**Generated:** 2026-04-18 ## OVERVIEW @@ -97,7 +97,7 @@ | artistry | gemini-3.1-pro high | Creative approaches | | quick | gpt-5.4-mini | Trivial tasks | | unspecified-low | claude-sonnet-4-6 | Moderate effort | -| unspecified-high | claude-opus-4-6 max | High effort | +| unspecified-high | claude-opus-4-7 max | High effort | | writing | gemini-3-flash | Documentation | ## HOW TO ADD A TOOL diff --git a/src/tools/background-task/create-background-cancel.ts b/src/tools/background-task/create-background-cancel.ts index 49fc4e5bb..a61c280f8 100644 --- a/src/tools/background-task/create-background-cancel.ts +++ b/src/tools/background-task/create-background-cancel.ts @@ -59,7 +59,7 @@ export function createBackgroundCancel(manager: BackgroundManager, _client: Back To continue a cancelled task, use: \`\`\` -task(session_id="", prompt="Continue: ") +task(task_id="", prompt="Continue: ") \`\`\` Continuable sessions: diff --git a/src/tools/background-task/create-background-output.metadata.test.ts b/src/tools/background-task/create-background-output.metadata.test.ts index 5111667bb..7b031abee 100644 --- a/src/tools/background-task/create-background-output.metadata.test.ts +++ b/src/tools/background-task/create-background-output.metadata.test.ts @@ -59,7 +59,7 @@ describe("createBackgroundOutput metadata", () => { agent: "test-agent", category: undefined, description: "background task", - task_id: "task-1", + backgroundTaskId: "task-1", }, }) diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts index 925db344a..56634b191 100644 --- a/src/tools/background-task/create-background-output.ts +++ b/src/tools/background-task/create-background-output.ts @@ -1,6 +1,6 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { BackgroundTask } from "../../features/background-agent" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import type { BackgroundOutputArgs } from "./types" import type { BackgroundOutputClient, BackgroundOutputManager } from "./clients" import { BACKGROUND_OUTPUT_DESCRIPTION } from "./constants" @@ -23,13 +23,6 @@ type ToolContextWithMetadata = { call_id?: string } -function resolveToolCallID(ctx: ToolContextWithMetadata): string | undefined { - if (typeof ctx.callID === "string" && ctx.callID.trim() !== "") return ctx.callID - if (typeof ctx.callId === "string" && ctx.callId.trim() !== "") return ctx.callId - if (typeof ctx.call_id === "string" && ctx.call_id.trim() !== "") return ctx.call_id - return undefined -} - function formatResolvedTitle(task: BackgroundTask): string { const label = task.agent === SISYPHUS_JUNIOR_AGENT && task.category ? task.category : task.agent return `${label} - ${task.description}` @@ -73,19 +66,14 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: const meta = { title: formatResolvedTitle(task), metadata: { - task_id: task.id, + backgroundTaskId: task.id, agent: task.agent, category: task.category, description: task.description, - ...(task.sessionID ? { sessionId: task.sessionID } : {}), + ...(task.sessionID ? { sessionId: task.sessionID, taskId: task.sessionID } : {}), } as Record, } - ctx.metadata?.(meta) - - const callID = resolveToolCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, meta) - } + await publishToolMetadata(ctx, meta) const shouldBlock = args.block === true const timeoutMs = Math.min(args.timeout ?? 60000, 600000) diff --git a/src/tools/background-task/create-background-task.ts b/src/tools/background-task/create-background-task.ts index 0d2c38f0f..cd892e6a3 100644 --- a/src/tools/background-task/create-background-task.ts +++ b/src/tools/background-task/create-background-task.ts @@ -4,7 +4,7 @@ import type { BackgroundTaskArgs } from "./types" import { BACKGROUND_TASK_DESCRIPTION } from "./constants" import { resolveMessageContext } from "../../features/hook-message-injector" import { getSessionAgent } from "../../features/claude-code-session-state" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { log } from "../../shared/logger" import { delay } from "./delay" import { getMessageDir } from "./message-dir" @@ -100,11 +100,7 @@ export function createBackgroundTask( ...(sessionId ? { sessionId } : {}), }, } - ctx.metadata?.(bgMeta) - - if (ctx.callID) { - storeToolMetadata(ctx.sessionID, ctx.callID, bgMeta) - } + await publishToolMetadata(ctx, bgMeta) return `Background task launched successfully. diff --git a/src/tools/call-omo-agent/sync-executor.ts b/src/tools/call-omo-agent/sync-executor.ts index 23089d8ea..56e22a80a 100644 --- a/src/tools/call-omo-agent/sync-executor.ts +++ b/src/tools/call-omo-agent/sync-executor.ts @@ -1,7 +1,6 @@ import type { CallOmoAgentArgs } from "./types" import type { PluginInput } from "@opencode-ai/plugin" import { subagentSessions, syncSubagentSessions } from "../../features/claude-code-session-state" -import { clearSessionFallbackChain, setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { getAgentToolRestrictions, log } from "../../shared" import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers" import type { DelegatedModelConfig } from "../../shared/model-resolution-types" @@ -19,8 +18,8 @@ type ExecuteSyncDeps = { createOrGetSession: typeof createOrGetSession waitForCompletion: typeof waitForCompletion processMessages: typeof processMessages - setSessionFallbackChain: typeof setSessionFallbackChain - clearSessionFallbackChain: typeof clearSessionFallbackChain + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => void + clearSessionFallbackChain: (sessionID: string) => void } type SpawnReservation = { @@ -32,8 +31,8 @@ const defaultDeps: ExecuteSyncDeps = { createOrGetSession, waitForCompletion, processMessages, - setSessionFallbackChain, - clearSessionFallbackChain, + setSessionFallbackChain: () => {}, + clearSessionFallbackChain: () => {}, } function buildPromptGenerationParams(model: DelegatedModelConfig | undefined): Record { diff --git a/src/tools/call-omo-agent/tools.ts b/src/tools/call-omo-agent/tools.ts index 802ac0ba0..51ea8730c 100644 --- a/src/tools/call-omo-agent/tools.ts +++ b/src/tools/call-omo-agent/tools.ts @@ -1,7 +1,8 @@ import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin" import { ALLOWED_AGENTS, CALL_OMO_AGENT_DESCRIPTION } from "./constants" -import type { AllowedAgentType, CallOmoAgentArgs, ToolContextWithMetadata } from "./types" +import type { CallOmoAgentArgs, ToolContextWithMetadata } from "./types" import type { BackgroundManager } from "../../features/background-agent" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { CategoriesConfig, AgentOverrides } from "../../config/schema" import type { DelegatedModelConfig } from "../../shared/model-resolution-types" import type { FallbackEntry } from "../../shared/model-requirements" @@ -11,10 +12,27 @@ import { normalizeFallbackModels } from "../../shared/model-resolver" import { buildFallbackChainFromModels } from "../../shared/fallback-chain-from-models" import { log } from "../../shared" import { CONFIG_BASENAME } from "../../shared/plugin-identity" -import { parseModelString } from "../delegate-task/model-string-parser" +import { parseModelString } from "../../shared" import { executeBackground } from "./background-executor" import { executeSync } from "./sync-executor" import { resolveCallableAgents } from "./agent-resolver" +import { createOrGetSession } from "./session-creator" +import { processMessages } from "./message-processor" +import { waitForCompletion } from "./completion-poller" + +function createSyncExecutorDeps(modelFallbackControllerAccessor?: ModelFallbackControllerAccessor) { + return { + createOrGetSession, + waitForCompletion, + processMessages, + setSessionFallbackChain: (sessionID: string, fallbackChain: FallbackEntry[] | undefined) => { + modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain) + }, + clearSessionFallbackChain: (sessionID: string) => { + modelFallbackControllerAccessor?.clearSessionFallbackChain(sessionID) + }, + } +} function resolveModelAndFallbackChain(args: { subagentType: string @@ -82,6 +100,7 @@ export function createCallOmoAgent( disabledAgents: string[] = [], agentOverrides?: AgentOverrides, userCategories?: CategoriesConfig, + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor, ): ToolDefinition { const agentDescriptions = ALLOWED_AGENTS.map( (name) => `- ${name}: Specialized agent for ${name} tasks`, @@ -158,14 +177,30 @@ export function createCallOmoAgent( let spawnReservation: Awaited> | undefined try { spawnReservation = await backgroundManager.reserveSubagentSpawn(toolCtx.sessionID) - return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, spawnReservation, resolvedModel) + return await executeSync( + args, + toolCtx, + ctx, + createSyncExecutorDeps(modelFallbackControllerAccessor), + fallbackChain, + spawnReservation, + resolvedModel, + ) } catch (error) { spawnReservation?.rollback() return `Error: ${error instanceof Error ? error.message : String(error)}` } } - return await executeSync(args, toolCtx, ctx, undefined, fallbackChain, undefined, resolvedModel) + return await executeSync( + args, + toolCtx, + ctx, + createSyncExecutorDeps(modelFallbackControllerAccessor), + fallbackChain, + undefined, + resolvedModel, + ) }, }); } diff --git a/src/tools/delegate-task/AGENTS.md b/src/tools/delegate-task/AGENTS.md index f160a7d7b..e928a37e6 100644 --- a/src/tools/delegate-task/AGENTS.md +++ b/src/tools/delegate-task/AGENTS.md @@ -32,7 +32,7 @@ sync-task.ts → sync-session-creator.ts → sync-prompt-sender.ts → sync-session-poller.ts → sync-result-fetcher.ts ``` -Each file handles one step. `sync-continuation.ts` handles session continuation (resume with session_id). +Each file handles one step. `sync-continuation.ts` handles session continuation (resume with task_id). ## BACKGROUND EXECUTION @@ -40,7 +40,7 @@ Each file handles one step. `sync-continuation.ts` handles session continuation background-task.ts → BackgroundManager.launch() → (async polling) → background-continuation.ts ``` -`background-continuation.ts` handles `session_id` resume for existing background tasks. +`background-continuation.ts` handles `task_id` resume for existing background tasks. ## CATEGORY RESOLUTION diff --git a/src/tools/delegate-task/anthropic-categories.ts b/src/tools/delegate-task/anthropic-categories.ts index e6b0894e3..cb5a88876 100644 --- a/src/tools/delegate-task/anthropic-categories.ts +++ b/src/tools/delegate-task/anthropic-categories.ts @@ -47,7 +47,7 @@ export const ANTHROPIC_CATEGORIES: BuiltinCategoryDefinition[] = [ }, { name: "unspecified-high", - config: { model: "anthropic/claude-opus-4-6", variant: "max" }, + config: { model: "anthropic/claude-opus-4-7", variant: "max" }, description: "Tasks that don't fit other categories, high effort required", promptAppend: UNSPECIFIED_HIGH_CATEGORY_PROMPT_APPEND, }, diff --git a/src/tools/delegate-task/background-continuation.test.ts b/src/tools/delegate-task/background-continuation.test.ts index f97c2d143..2b0e768c9 100644 --- a/src/tools/delegate-task/background-continuation.test.ts +++ b/src/tools/delegate-task/background-continuation.test.ts @@ -30,7 +30,7 @@ describe("executeBackgroundContinuation - subagent metadata", () => { } const args = { - session_id: "ses_resumed_123", + task_id: "ses_resumed_123", prompt: "continue working", description: "resume oracle", load_skills: [], @@ -76,7 +76,7 @@ describe("executeBackgroundContinuation - subagent metadata", () => { } const args = { - session_id: "ses_resumed_456", + task_id: "ses_resumed_456", prompt: "continue", description: "resume task", load_skills: [], diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 0d365d964..1d0aa94f6 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -1,68 +1,87 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" -import { resolveCallID } from "./resolve-call-id" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" +import { getTaskID } from "./task-id" export async function executeBackgroundContinuation( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, executorCtx: ExecutorContext, - parentContext: ParentContext + parentContext: ParentContext, + systemContent?: string ): Promise { const { manager } = executorCtx + const taskID = getTaskID(args) try { + if (!taskID) { + throw new Error("task_id is required to continue a background task") + } + + const effectivePrompt = systemContent + ? `${systemContent}\n\n${args.prompt}` + : args.prompt + const task = await manager.resume({ - sessionId: args.session_id!, - prompt: args.prompt, + sessionId: taskID, + prompt: effectivePrompt, parentSessionID: parentContext.sessionID, parentMessageID: parentContext.messageID, parentModel: parentContext.model, parentAgent: parentContext.agent, parentTools: getSessionTools(parentContext.sessionID), }) + const sessionId = task.sessionID + const backgroundTaskId = task.id + const resolvedModel = resolveMetadataModel(task.model, parentContext.model) const bgContMeta = { - title: `Continue: ${task.description}`, + title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, agent: task.agent, + ...(task.category !== undefined ? { category: task.category } : {}), + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, - sessionId: task.sessionID, + taskId: sessionId, + backgroundTaskId, + sessionId, command: args.command, - model: task.model ? { providerID: task.model.providerID, modelID: task.model.modelID } : undefined, + model: resolvedModel, }, } - await ctx.metadata?.(bgContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgContMeta) - } + await publishToolMetadata(ctx, bgContMeta) return `Background task continued. -Task ID: ${task.id} +Task ID: ${backgroundTaskId} Description: ${task.description} Agent: ${task.agent} Status: ${task.status} Agent continues with full previous context preserved. -System notifies on completion. Use \`background_output\` with task_id="${task.id}" to check. +System notifies on completion. Use \`background_output\` with task_id="${backgroundTaskId}" to check. Do NOT call background_output now. Wait for notification first. - -session_id: ${task.sessionID} -${task.agent ? `subagent: ${task.agent}\n` : ""}` +${buildTaskMetadataBlock({ + sessionId, + taskId: sessionId, + backgroundTaskId, + agent: task.agent, + category: task.category, + })}` } catch (error) { return formatDetailedError(error, { operation: "Continue background task", args, - sessionID: args.session_id, + sessionID: taskID, }) } } diff --git a/src/tools/delegate-task/background-task.test.ts b/src/tools/delegate-task/background-task.test.ts index 84a7bc644..3837dbb6e 100644 --- a/src/tools/delegate-task/background-task.test.ts +++ b/src/tools/delegate-task/background-task.test.ts @@ -104,11 +104,14 @@ describeFn("executeBackgroundTask output/session metadata compatibility", () => //#then - output and metadata should include canonical session linkage expectFn(result).toContain("") expectFn(result).toContain("session_id: ses_sub_123") - expectFn(result).toContain("task_id: bg_resolved") + expectFn(result).toContain("task_id: ses_sub_123") expectFn(result).toContain("background_task_id: bg_resolved") + expectFn(result).toContain("subagent: explore") expectFn(result).toContain("Background Task ID: bg_resolved") expectFn(metadataCalls).toHaveLength(1) expectFn(metadataCalls[0].metadata.sessionId).toBe("ses_sub_123") + expectFn(metadataCalls[0].metadata.taskId).toBe("ses_sub_123") + expectFn(metadataCalls[0].metadata.backgroundTaskId).toBe("bg_resolved") }) testFn("captures late-resolved session id and emits synced metadata", async () => { @@ -152,10 +155,12 @@ describeFn("executeBackgroundTask output/session metadata compatibility", () => //#then - late session id still propagates to task metadata contract expectFn(result).toContain("session_id: ses_late_123") - expectFn(result).toContain("task_id: bg_late") + expectFn(result).toContain("task_id: ses_late_123") expectFn(result).toContain("background_task_id: bg_late") expectFn(metadataCalls).toHaveLength(1) expectFn(metadataCalls[0].metadata.sessionId).toBe("ses_late_123") + expectFn(metadataCalls[0].metadata.taskId).toBe("ses_late_123") + expectFn(metadataCalls[0].metadata.backgroundTaskId).toBe("bg_late") }) testFn("passes question-deny session permission when launching delegate task", async () => { diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 184325ec9..e4ec2db38 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -3,14 +3,26 @@ import type { ExecutorContext, ParentContext } from "./executor-types" import type { FallbackEntry } from "../../shared/model-requirements" import { getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" -import { setSessionFallbackChain } from "../../hooks/model-fallback/hook" import { stripAgentListSortPrefix } from "../../shared/agent-display-names" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" + +function registerBackgroundSessionContext(args: { + sessionId: string + fallbackChain?: FallbackEntry[] + category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] +}): void { + args.modelFallbackControllerAccessor?.setSessionFallbackChain(args.sessionId, args.fallbackChain) + if (args.category) { + SessionCategoryRegistry.register(args.sessionId, args.category) + } +} function continueSessionSetup(args: { taskID: string @@ -18,6 +30,7 @@ function continueSessionSetup(args: { timing: ReturnType fallbackChain?: FallbackEntry[] category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] }): void { if (!args.fallbackChain && !args.category) { return @@ -40,15 +53,50 @@ function continueSessionSetup(args: { continue } - setSessionFallbackChain(sessionId, args.fallbackChain) - if (args.category) { - SessionCategoryRegistry.register(sessionId, args.category) - } + registerBackgroundSessionContext({ + sessionId, + fallbackChain: args.fallbackChain, + category: args.category, + modelFallbackControllerAccessor: args.modelFallbackControllerAccessor, + }) return } })() } +async function waitForBackgroundSessionStart(args: { + taskId: string + initialSessionId?: string + manager: ExecutorContext["manager"] + timing: ReturnType + abortSignal?: AbortSignal + onAbort: () => void +}): Promise { + const waitStart = Date.now() + let sessionId = args.initialSessionId + + while (!sessionId && Date.now() - waitStart < args.timing.WAIT_FOR_SESSION_TIMEOUT_MS) { + const updated = args.manager.getTask(args.taskId) + if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") { + return undefined + } + + sessionId = updated?.sessionID + if (sessionId) { + return sessionId + } + + if (args.abortSignal?.aborted) { + args.onAbort() + return undefined + } + + await new Promise(resolve => setTimeout(resolve, args.timing.WAIT_FOR_SESSION_INTERVAL_MS)) + } + + return sessionId +} + export async function executeBackgroundTask( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, @@ -87,61 +135,68 @@ export async function executeBackgroundTask( // BackgroundManager.launch() returns immediately (pending) before the session exists, // so we must wait briefly for the session to be created to set metadata correctly. const timing = getTimingConfig() - const waitStart = Date.now() - let sessionId = task.sessionID - while (!sessionId && Date.now() - waitStart < timing.WAIT_FOR_SESSION_TIMEOUT_MS) { - const updated = manager.getTask(task.id) - if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") { - return `Task failed to start (status: ${updated.status}).\n\nTask ID: ${task.id}` - } - sessionId = updated?.sessionID - if (sessionId) { - break - } - if (ctx.abort?.aborted) { + let sessionId = await waitForBackgroundSessionStart({ + taskId: task.id, + initialSessionId: task.sessionID, + manager, + timing, + abortSignal: ctx.abort, + onAbort: () => { continueSessionSetup({ taskID: task.id, manager, timing, fallbackChain, category: args.category, + modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, }) - break - } - await new Promise(resolve => setTimeout(resolve, timing.WAIT_FOR_SESSION_INTERVAL_MS)) + }, + }) + + const updatedTask = typeof manager.getTask === "function" + ? manager.getTask(task.id) + : undefined + if (!sessionId && (updatedTask?.status === "error" || updatedTask?.status === "cancelled" || updatedTask?.status === "interrupt")) { + return `Task failed to start (status: ${updatedTask.status}).\n\nTask ID: ${task.id}` } if (sessionId) { - setSessionFallbackChain(sessionId, fallbackChain) - } - if (args.category && sessionId) { - SessionCategoryRegistry.register(sessionId, args.category) + registerBackgroundSessionContext({ + sessionId, + fallbackChain, + category: args.category, + modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, + }) } + const resolvedModel = resolveMetadataModel(categoryModel, parentContext.model) const metadata = { prompt: args.prompt, agent: task.agent, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, command: args.command, - ...(sessionId ? { sessionId } : {}), - ...(categoryModel ? { model: { providerID: categoryModel.providerID, modelID: categoryModel.modelID } } : {}), + ...(sessionId ? { taskId: sessionId, sessionId } : {}), + backgroundTaskId: task.id, + ...(resolvedModel ? { model: resolvedModel } : {}), } - const unstableMeta = { + await publishToolMetadata(ctx, { title: args.description, metadata, - } - await ctx.metadata?.(unstableMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, unstableMeta) - } + }) const taskMetadataBlock = sessionId - ? `\n\n\nsession_id: ${sessionId}\ntask_id: ${task.id}\nbackground_task_id: ${task.id}\n` + ? `\n\n${buildTaskMetadataBlock({ + sessionId, + taskId: sessionId, + backgroundTaskId: task.id, + agent: task.agent, + category: args.category, + })}` : "" return `Background task launched. diff --git a/src/tools/delegate-task/category-resolver.test.ts b/src/tools/delegate-task/category-resolver.test.ts index 4a52f4158..ffe59d705 100644 --- a/src/tools/delegate-task/category-resolver.test.ts +++ b/src/tools/delegate-task/category-resolver.test.ts @@ -99,7 +99,7 @@ describe("resolveCategoryExecution", () => { const executorCtx = createMockExecutorContext() executorCtx.userCategories = { deep: { - model: "quotio/claude-opus-4-6", + model: "quotio/claude-opus-4-7", fallback_models: ["quotio/kimi-k2.5", "openai/gpt-5.2(high)"], }, } diff --git a/src/tools/delegate-task/category-resolver.ts b/src/tools/delegate-task/category-resolver.ts index bfc4d1896..25f4e8a37 100644 --- a/src/tools/delegate-task/category-resolver.ts +++ b/src/tools/delegate-task/category-resolver.ts @@ -5,7 +5,7 @@ import type { FallbackEntry } from "../../shared/model-requirements" import { mergeCategories } from "../../shared/merge-categories" import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" import { resolveCategoryConfig } from "./categories" -import { parseModelString } from "./model-string-parser" +import { parseModelString } from "../../shared/model-string-parser" import { CATEGORY_MODEL_REQUIREMENTS } from "../../shared/model-requirements" import { normalizeFallbackModels, flattenToFallbackModelStrings } from "../../shared/model-resolver" import { buildFallbackChainFromModels, findMostSpecificFallbackEntry } from "../../shared/fallback-chain-from-models" diff --git a/src/tools/delegate-task/error-formatting.ts b/src/tools/delegate-task/error-formatting.ts index f2c24abc5..9b7b98ab2 100644 --- a/src/tools/delegate-task/error-formatting.ts +++ b/src/tools/delegate-task/error-formatting.ts @@ -1,4 +1,5 @@ import type { DelegateTaskArgs } from "./types" +import { getTaskID } from "./task-id" /** * Context for error formatting. @@ -35,8 +36,9 @@ export function formatDetailedError(error: unknown, ctx: ErrorContext): string { lines.push(`- subagent_type: ${ctx.args.subagent_type ?? "(none)"}`) lines.push(`- run_in_background: ${ctx.args.run_in_background}`) lines.push(`- load_skills: [${ctx.args.load_skills?.join(", ") ?? ""}]`) - if (ctx.args.session_id) { - lines.push(`- session_id: ${ctx.args.session_id}`) + const taskID = getTaskID(ctx.args) + if (taskID) { + lines.push(`- task_id: ${taskID}`) } } diff --git a/src/tools/delegate-task/executor-types.ts b/src/tools/delegate-task/executor-types.ts index bfa7fc70b..8b430c9ce 100644 --- a/src/tools/delegate-task/executor-types.ts +++ b/src/tools/delegate-task/executor-types.ts @@ -1,5 +1,6 @@ import type { BackgroundManager } from "../../features/background-agent" import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { OpencodeClient } from "./types" export interface ExecutorContext { @@ -12,6 +13,7 @@ export interface ExecutorContext { browserProvider?: BrowserAutomationProvider agentOverrides?: AgentOverrides sisyphusAgentConfig?: SisyphusAgentConfig + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor onSyncSessionCreated?: (event: { sessionID: string; parentID: string; title: string }) => Promise syncPollTimeoutMs?: number } diff --git a/src/tools/delegate-task/metadata-model-unification.test.ts b/src/tools/delegate-task/metadata-model-unification.test.ts index 2cb67a8d2..5e913b5e7 100644 --- a/src/tools/delegate-task/metadata-model-unification.test.ts +++ b/src/tools/delegate-task/metadata-model-unification.test.ts @@ -1,9 +1,10 @@ -const { describe, test, expect, mock } = require("bun:test") +const { describe, test, expect } = require("bun:test") import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ParentContext } from "./executor-types" const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } +const MODEL_WITH_VARIANT = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" } function makeMockCtx(): ToolContextWithMetadata & { captured: any[] } { const captured: any[] = [] @@ -89,7 +90,7 @@ describe("metadata model unification", () => { id: "bg_unstable", description: "test", agent: "explore", status: "completed", sessionID: "ses_unstable", model: MODEL, } - const result = await executeUnstableAgentTask( + await executeUnstableAgentTask( args, ctx, { manager: { @@ -122,7 +123,7 @@ describe("metadata model unification", () => { const ctx = makeMockCtx() const args: DelegateTaskArgs = { description: "continue", prompt: "keep going", - load_skills: [], run_in_background: true, session_id: "ses_resumed", + load_skills: [], run_in_background: true, task_id: "ses_resumed", } await executeBackgroundContinuation(args, ctx, { @@ -144,7 +145,7 @@ describe("metadata model unification", () => { const ctx = makeMockCtx() const args: DelegateTaskArgs = { description: "continue", prompt: "keep going", - load_skills: [], run_in_background: false, session_id: "ses_cont", + load_skills: [], run_in_background: false, task_id: "ses_cont", } const deps = { @@ -161,7 +162,7 @@ describe("metadata model unification", () => { prompt: async () => ({}), }, }, - } as any, deps) + } as any, parentContext, deps) const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) expect(meta).toBeDefined() @@ -169,4 +170,323 @@ describe("metadata model unification", () => { }) }) }) + + describe("#given categoryModel is undefined but parent.model is set", () => { + describe("#when executors publish metadata", () => { + test("#then sync-task metadata falls back to parent.model", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + subagent_type: "explore", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", undefined, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then background-task metadata falls back to parent.model", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_1", description: "test", agent: "explore", + status: "pending", sessionID: "ses_bg", + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", undefined, undefined) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then unstable-agent-task metadata falls back to parent.model", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", undefined, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then background-continuation metadata falls back to parent.model when task.model missing", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_2", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed", + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + + test("#then sync-continuation metadata falls back to parent.model when resume model missing", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ data: [] }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL) + }) + }) + }) + + describe("#given both categoryModel and parent.model are undefined", () => { + test("#when sync-task runs #then metadata.model is undefined without crashing", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + subagent_type: "explore", load_skills: [], run_in_background: false, + } + + const parentContextWithoutModel: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContextWithoutModel, "explore", undefined, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toBeUndefined() + }) + }) + + describe("#given category model with variant", () => { + describe("#when executors publish metadata", () => { + test("#then sync-task metadata includes variant", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync_variant" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync_variant" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", MODEL_WITH_VARIANT, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then background-task metadata includes variant", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_variant", description: "test", agent: "explore", + status: "pending", sessionID: "ses_bg_variant", model: MODEL_WITH_VARIANT, + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", MODEL_WITH_VARIANT, undefined) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then unstable-agent-task metadata includes variant", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "visual-engineering", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_variant", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable_variant", model: MODEL_WITH_VARIANT, + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_variant: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", MODEL_WITH_VARIANT, undefined, "google/gemini-3.1-pro high", + ) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then background-continuation metadata includes variant from task", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_variant", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resume_variant", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_variant", model: MODEL_WITH_VARIANT, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + + test("#then sync-continuation metadata includes variant from resumed session", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_variant", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL_WITH_VARIANT, providerID: "google", modelID: "gemini-3.1-pro" } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((metadataEvent: any) => metadataEvent.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.model).toEqual(MODEL_WITH_VARIANT) + }) + }) + }) }) diff --git a/src/tools/delegate-task/metadata-task-id-consistency.test.ts b/src/tools/delegate-task/metadata-task-id-consistency.test.ts new file mode 100644 index 000000000..1f0d985d5 --- /dev/null +++ b/src/tools/delegate-task/metadata-task-id-consistency.test.ts @@ -0,0 +1,462 @@ +const { describe, test, expect } = require("bun:test") + +import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" +import type { ParentContext } from "./executor-types" + +const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } + +function makeMockCtx(): ToolContextWithMetadata & { captured: any[] } { + const captured: any[] = [] + return { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + abort: new AbortController().signal, + callID: "call_001", + metadata: async (input: any) => { captured.push(input) }, + captured, + } +} + +const parentContext: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + model: MODEL, +} + +describe("taskId and backgroundTaskId metadata consistency", () => { + describe("#given sync-task runs", () => { + test("#when publishing metadata #then taskId equals sessionId", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "explore", MODEL, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_sync") + expect(meta.metadata.sessionId).toBe("ses_sync") + expect(meta.metadata.taskId).toBe(meta.metadata.sessionId) + }) + }) + + describe("#given background-task runs", () => { + test("#when publishing metadata #then taskId is sessionID and backgroundTaskId is task.id", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + load_skills: [], run_in_background: true, subagent_type: "explore", + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_abc123", description: "test", agent: "explore", + status: "pending", sessionID: "ses_xyz789", + }), + getTask: () => undefined, + }, + } as any, parentContext, "explore", MODEL, undefined) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_xyz789") + expect(meta.metadata.sessionId).toBe("ses_xyz789") + expect(meta.metadata.backgroundTaskId).toBe("bg_abc123") + }) + }) + + describe("#given unstable-agent-task runs", () => { + test("#when publishing metadata #then taskId and backgroundTaskId are both included", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "test", prompt: "do it", + category: "quick", load_skills: [], run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_abc", description: "test", agent: "explore", + status: "completed", sessionID: "ses_unstable_xyz", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_xyz: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "explore", MODEL, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_unstable_xyz") + expect(meta.metadata.sessionId).toBe("ses_unstable_xyz") + expect(meta.metadata.backgroundTaskId).toBe("bg_unstable_abc") + }) + }) + + describe("#given background-continuation runs", () => { + test("#when publishing metadata #then taskId is sessionID and backgroundTaskId is bg.id", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_resumed_x") + expect(meta.metadata.sessionId).toBe("ses_resumed_x") + expect(meta.metadata.backgroundTaskId).toBe("bg_resumed_y") + }) + + test("#when resumed task has category #then metadata.category equals task.category", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: true, task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, category: "deep", + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.category).toBe("deep") + }) + + test("#when publishing metadata with requested_subagent_type #then metadata.requested_subagent_type preserves original", async () => { + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args = { + description: "continue", + prompt: "keep going", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: true, + task_id: "ses_resumed_x", + } + + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_resumed_y", description: "continue", agent: "explore", + status: "running", sessionID: "ses_resumed_x", model: MODEL, + }), + }, + } as any, parentContext) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + }) + + describe("#given sync-continuation runs", () => { + test("#when publishing metadata #then taskId is sessionID", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_abc", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((m: any) => m.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.taskId).toBe("ses_cont_abc") + expect(meta.metadata.sessionId).toBe("ses_cont_abc") + }) + + test("#when resumeAgent is resolved #then metadata.agent equals resumeAgent", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + load_skills: [], run_in_background: false, task_id: "ses_cont_abc", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.agent).toBe("explore") + }) + + test("#when called with category arg #then metadata.category equals args.category", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", prompt: "keep going", + category: "quick", load_skills: [], run_in_background: false, task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.category).toBe("quick") + }) + + test("#when publishing metadata with requested_subagent_type #then metadata.requested_subagent_type preserves original", async () => { + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args = { + description: "continue", + prompt: "keep going", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + task_id: "ses_cont", + } + + const deps = { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ + data: [{ info: { agent: "explore", model: MODEL } }], + }), + prompt: async () => ({}), + }, + }, + } as any, parentContext, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + }) + + describe("#given user calls with requested_subagent_type plus category", () => { + test("#when sync-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeSyncTask } = require("./sync-task") + const ctx = makeMockCtx() + const deps = { + createSyncSession: async () => ({ ok: true, sessionID: "ses_sync" }), + sendSyncPrompt: async () => null, + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + } + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + } + + await executeSyncTask(args, ctx, { + client: { session: { create: async () => ({ data: { id: "ses_sync" } }) } }, + directory: "/tmp", + onSyncSessionCreated: null, + }, parentContext, "Sisyphus-Junior", MODEL, undefined, undefined, undefined, deps) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + + test("#when background-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeBackgroundTask } = require("./background-task") + const ctx = makeMockCtx() + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: true, + } + + await executeBackgroundTask(args, ctx, { + manager: { + launch: async () => ({ + id: "bg_abc123", description: "test", agent: "Sisyphus-Junior", + status: "pending", sessionID: "ses_xyz789", + }), + getTask: () => undefined, + }, + } as any, parentContext, "Sisyphus-Junior", MODEL, undefined) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + + test("#when unstable-agent-task publishes metadata #then metadata.requested_subagent_type preserves original", async () => { + const { executeUnstableAgentTask } = require("./unstable-agent-task") + const ctx = makeMockCtx() + const args = { + description: "test", + prompt: "do it", + category: "quick", + requested_subagent_type: "oracle", + load_skills: [], + run_in_background: false, + } + + const launchedTask = { + id: "bg_unstable_abc", description: "test", agent: "Sisyphus-Junior", + status: "completed", sessionID: "ses_unstable_xyz", + } + + await executeUnstableAgentTask( + args, ctx, + { + manager: { + launch: async () => launchedTask, + getTask: () => launchedTask, + }, + client: { + session: { + status: async () => ({ data: { ses_unstable_xyz: { type: "idle" } } }), + messages: async () => ({ + data: [{ + info: { role: "assistant", time: { created: 1 } }, + parts: [{ type: "text", text: "done" }], + }], + }), + }, + }, + syncPollTimeoutMs: 100, + } as any, + parentContext, "Sisyphus-Junior", MODEL, undefined, "anthropic/claude-sonnet-4-6", + ) + + const meta = ctx.captured.find((item: any) => item.metadata?.sessionId) + expect(meta).toBeDefined() + expect(meta.metadata.requested_subagent_type).toBe("oracle") + }) + }) + + describe("#given background_output runs", () => { + test("#when publishing metadata #then backgroundTaskId is task.id not task_id", async () => { + const { createBackgroundOutput } = require("../background-task/create-background-output") + const ctx = makeMockCtx() + const manager = { + getTask: (id: string) => ({ + id, + sessionID: "ses_bg_session", + agent: "explore", + category: "deep", + description: "test", + status: "completed" as const, + }), + } + const client = { + session: { + messages: async () => ({ data: [] }), + }, + } + + const bgOutput = createBackgroundOutput(manager as any, client as any) + await bgOutput.execute({ task_id: "bg_output_xyz" } as any, ctx as any) + + const meta = ctx.captured.find((m: any) => m.metadata?.backgroundTaskId) + expect(meta).toBeDefined() + expect(meta.metadata.backgroundTaskId).toBe("bg_output_xyz") + expect(meta.metadata.sessionId).toBe("ses_bg_session") + expect(meta.metadata.taskId).toBe("ses_bg_session") + }) + }) +}) diff --git a/src/tools/delegate-task/model-selection.ts b/src/tools/delegate-task/model-selection.ts index cef7df752..43fa4741b 100644 --- a/src/tools/delegate-task/model-selection.ts +++ b/src/tools/delegate-task/model-selection.ts @@ -4,7 +4,7 @@ import { fuzzyMatchModel } from "../../shared/model-availability" import { transformModelForProvider } from "../../shared/provider-model-id-transform" import { hasConnectedProvidersCache, hasProviderModelsCache, readConnectedProvidersCache } from "../../shared/connected-providers-cache" import { log } from "../../shared/logger" -import { parseModelString, parseVariantFromModelID } from "./model-string-parser" +import { parseModelString, parseVariantFromModelID } from "../../shared/model-string-parser" function isExplicitHighModel(model: string): boolean { return /(?:^|\/)[^/]+-high$/.test(model) diff --git a/src/tools/delegate-task/oracle-gap-closure.test.ts b/src/tools/delegate-task/oracle-gap-closure.test.ts new file mode 100644 index 000000000..eb8c3fe1c --- /dev/null +++ b/src/tools/delegate-task/oracle-gap-closure.test.ts @@ -0,0 +1,245 @@ +declare const require: NodeJS.Require + +const { describe, test, expect, beforeEach, afterEach, spyOn, mock } = require("bun:test") + +import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" +import type { ParentContext } from "./executor-types" +import * as executor from "./executor" + +const runtimeRequire = require as NodeJS.Require & { cache?: Record } +const MODEL = { providerID: "openai", modelID: "gpt-5.4" } + +function clearRequireCache(modulePath: string): void { + const resolvedPath = runtimeRequire.resolve(modulePath) + if (runtimeRequire.cache?.[resolvedPath]) { + delete runtimeRequire.cache[resolvedPath] + } +} + +function makeMockCtx(): ToolContextWithMetadata & { + captured: Array<{ title?: string; metadata?: Record }> +} { + const captured: Array<{ title?: string; metadata?: Record }> = [] + + return { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + abort: new AbortController().signal, + callID: "call_001", + metadata: async (input) => { + captured.push(input) + }, + captured, + } +} + +const parentContext: ParentContext = { + sessionID: "ses_parent", + messageID: "msg_parent", + agent: "sisyphus", + model: MODEL, +} + +describe("delegate-task Oracle gap closure", () => { + beforeEach(() => { + mock.restore() + clearRequireCache("./tools") + }) + + afterEach(() => { + mock.restore() + clearRequireCache("./tools") + }) + + test("#given sync continuation message info has sibling variant #when metadata publishes #then model keeps variant", async () => { + //#given + const { executeSyncContinuation } = require("./sync-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + load_skills: [], + run_in_background: false, + task_id: "ses_cont_variant", + } + + //#when + await executeSyncContinuation(args, ctx, { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL, variant: "max" } }] }), + promptAsync: async () => ({}), + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }) + + //#then + const published = ctx.captured.find((item) => item.metadata?.sessionId === "ses_cont_variant") + expect(published?.metadata?.model).toEqual({ ...MODEL, variant: "max" }) + }) + + test("#given sync continuation category arg #when result returns task metadata block #then block includes category", async () => { + //#given + const { executeSyncContinuation } = require("./sync-continuation") + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + category: "quick", + load_skills: [], + run_in_background: false, + task_id: "ses_cont_category", + } + + //#when + const result = await executeSyncContinuation(args, makeMockCtx(), { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL } }] }), + promptAsync: async () => ({}), + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }) + + //#then + expect(result).toContain("") + expect(result).toContain("category: quick") + }) + + test("#given background continuation task category #when result returns task metadata block #then block includes category", async () => { + //#given + const { executeBackgroundContinuation } = require("./background-continuation") + const args: DelegateTaskArgs = { + description: "continue", + prompt: "keep going", + load_skills: [], + run_in_background: true, + task_id: "ses_bg_category", + } + + //#when + const result = await executeBackgroundContinuation(args, makeMockCtx(), { + manager: { + resume: async () => ({ + id: "bg_category", + description: "existing", + agent: "explore", + status: "running", + sessionID: "ses_bg_category", + category: "deep", + model: MODEL, + }), + }, + }, parentContext) + + //#then + expect(result).toContain("") + expect(result).toContain("category: deep") + }) + + test("#given background continuation description changed #when metadata publishes #then title uses args description", async () => { + //#given + const { executeBackgroundContinuation } = require("./background-continuation") + const ctx = makeMockCtx() + const args: DelegateTaskArgs = { + description: "new desc", + prompt: "keep going", + load_skills: [], + run_in_background: true, + task_id: "ses_bg_title", + } + + //#when + await executeBackgroundContinuation(args, ctx, { + manager: { + resume: async () => ({ + id: "bg_title", + description: "old desc", + agent: "explore", + status: "running", + sessionID: "ses_bg_title", + model: MODEL, + }), + }, + }, parentContext) + + //#then + const published = ctx.captured.find((item) => item.metadata?.sessionId === "ses_bg_title") + expect(published?.title).toBe("Continue: new desc") + }) + + test("#given sync continuation receives system content #when prompt is sent #then system content reaches prompt body", async () => { + //#given + const promptCalls: Array<{ body?: { system?: string } }> = [] + const { executeSyncContinuation } = require("./sync-continuation") + + //#when + await executeSyncContinuation({ + description: "continue", + prompt: "keep going", + load_skills: ["playwright"], + run_in_background: false, + task_id: "ses_sync_skills", + }, makeMockCtx(), { + client: { + session: { + messages: async () => ({ data: [{ info: { agent: "explore", model: MODEL } }] }), + promptAsync: async (input: { body?: { system?: string } }) => { + promptCalls.push(input) + return {} + }, + }, + }, + }, parentContext, { + pollSyncSession: async () => null, + fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }), + }, "skill instructions") + + //#then + expect(promptCalls[0]?.body?.system).toBe("skill instructions") + }) + + test("#given background continuation loads skills through tool entry #when task resumes #then skill content is threaded into resumed prompt", async () => { + //#given + const resumeCalls: Array<{ prompt?: string }> = [] + spyOn(executor, "resolveSkillContent").mockResolvedValue({ content: "skill instructions", contents: undefined, error: null }) + spyOn(executor, "resolveParentContext").mockResolvedValue(parentContext) + const { createDelegateTask } = require("./tools") + const delegateTask = createDelegateTask({ + directory: "/tmp", + manager: { + resume: async (input: { prompt?: string }) => { + resumeCalls.push(input) + return { + id: "bg_skills", + description: "existing", + agent: "explore", + status: "running", + sessionID: "ses_bg_skills", + model: MODEL, + } + }, + }, + client: {}, + }) + + //#when + await delegateTask.execute({ + description: "continue", + prompt: "keep going", + load_skills: ["playwright"], + run_in_background: true, + task_id: "ses_bg_skills", + }, makeMockCtx()) + + //#then + expect(resumeCalls[0]?.prompt).toContain("skill instructions") + expect(resumeCalls[0]?.prompt).toContain("keep going") + }) +}) diff --git a/src/tools/delegate-task/resolve-call-id.test.ts b/src/tools/delegate-task/resolve-call-id.test.ts deleted file mode 100644 index 7b4da140e..000000000 --- a/src/tools/delegate-task/resolve-call-id.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, test, expect } from "bun:test" -import { resolveCallID } from "./resolve-call-id" -import type { ToolContextWithMetadata } from "./types" - -describe("resolveCallID", () => { - function makeCtx(overrides: Partial = {}): ToolContextWithMetadata { - return { - sessionID: "ses_test", - messageID: "msg_test", - agent: "sisyphus", - abort: new AbortController().signal, - ...overrides, - } - } - - test("#given callID is set #then returns callID", () => { - const ctx = makeCtx({ callID: "call_abc" }) - expect(resolveCallID(ctx)).toBe("call_abc") - }) - - test("#given only callId is set #then returns callId", () => { - const ctx = makeCtx({ callId: "call_def" }) - expect(resolveCallID(ctx)).toBe("call_def") - }) - - test("#given only call_id is set #then returns call_id", () => { - const ctx = makeCtx({ call_id: "call_ghi" }) - expect(resolveCallID(ctx)).toBe("call_ghi") - }) - - test("#given callID and callId are both set #then prefers callID", () => { - const ctx = makeCtx({ callID: "preferred", callId: "fallback" }) - expect(resolveCallID(ctx)).toBe("preferred") - }) - - test("#given no call ID variants are set #then returns undefined", () => { - const ctx = makeCtx() - expect(resolveCallID(ctx)).toBeUndefined() - }) -}) diff --git a/src/tools/delegate-task/resolve-call-id.ts b/src/tools/delegate-task/resolve-call-id.ts deleted file mode 100644 index cfa3b747e..000000000 --- a/src/tools/delegate-task/resolve-call-id.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ToolContextWithMetadata } from "./types" - -export function resolveCallID(ctx: ToolContextWithMetadata): string | undefined { - return ctx.callID ?? ctx.callId ?? ctx.call_id -} diff --git a/src/tools/delegate-task/resolve-metadata-model.test.ts b/src/tools/delegate-task/resolve-metadata-model.test.ts new file mode 100644 index 000000000..3c13a7710 --- /dev/null +++ b/src/tools/delegate-task/resolve-metadata-model.test.ts @@ -0,0 +1,93 @@ +const { describe, test, expect } = require("bun:test") + +import { resolveMetadataModel } from "./resolve-metadata-model" + +const PRIMARY = { providerID: "openai", modelID: "gpt-5.4" } +const FALLBACK = { providerID: "anthropic", modelID: "claude-sonnet-4-6" } + +describe("resolveMetadataModel", () => { + describe("#given primary and fallback are both present", () => { + test("#when resolving #then returns primary", () => { + const result = resolveMetadataModel(PRIMARY, FALLBACK) + + expect(result).toEqual(PRIMARY) + }) + }) + + describe("#given only fallback is present", () => { + test("#when resolving #then returns fallback", () => { + const result = resolveMetadataModel(undefined, FALLBACK) + + expect(result).toEqual(FALLBACK) + }) + }) + + describe("#given only primary is present", () => { + test("#when resolving #then returns primary", () => { + const result = resolveMetadataModel(PRIMARY, undefined) + + expect(result).toEqual(PRIMARY) + }) + }) + + describe("#given both are undefined", () => { + test("#when resolving #then returns undefined", () => { + const result = resolveMetadataModel(undefined, undefined) + + expect(result).toBeUndefined() + }) + }) + + describe("#given primary has extra fields", () => { + test("#when resolving #then preserves variant and strips unrelated fields", () => { + const extended = { providerID: "openai", modelID: "gpt-5.4", variant: "high", temperature: 0.7 } as const + + const result = resolveMetadataModel(extended, undefined) + + expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.4", variant: "high" }) + }) + }) + + describe("#given primary has variant", () => { + test("#when resolving metadata model #then variant is preserved", () => { + const primary = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" } + + const result = resolveMetadataModel(primary, undefined) + + expect(result).toEqual({ providerID: "google", modelID: "gemini-3.1-pro", variant: "high" }) + }) + }) + + describe("#given primary lacks variant but fallback has variant", () => { + test("#when primary provided #then fallback variant is not used", () => { + const primary = { providerID: "google", modelID: "gemini-3.1-pro" } + const fallback = { providerID: "anthropic", modelID: "claude", variant: "max" } + + const result = resolveMetadataModel(primary, fallback) + + expect(result).toEqual({ providerID: "google", modelID: "gemini-3.1-pro" }) + expect(result?.variant).toBeUndefined() + }) + }) + + describe("#given primary is undefined and fallback has variant", () => { + test("#when resolving metadata model #then fallback variant is preserved", () => { + const fallback = { providerID: "anthropic", modelID: "claude", variant: "max" } + + const result = resolveMetadataModel(undefined, fallback) + + expect(result).toEqual({ providerID: "anthropic", modelID: "claude", variant: "max" }) + }) + }) + + describe("#given both lack variant", () => { + test("#when resolving metadata model #then variant is not on result", () => { + const primary = { providerID: "openai", modelID: "gpt-5.4" } + + const result = resolveMetadataModel(primary, undefined) + + expect(result).toEqual({ providerID: "openai", modelID: "gpt-5.4" }) + expect(result?.variant).toBeUndefined() + }) + }) +}) diff --git a/src/tools/delegate-task/resolve-metadata-model.ts b/src/tools/delegate-task/resolve-metadata-model.ts new file mode 100644 index 000000000..c35580142 --- /dev/null +++ b/src/tools/delegate-task/resolve-metadata-model.ts @@ -0,0 +1,44 @@ +import type { DelegatedModelConfig } from "./types" + +interface MetadataModel { + providerID: string + modelID: string + variant?: string +} + +type ModelLike = Pick | MetadataModel + +function isModelLike(value: unknown): value is ModelLike { + return typeof value === "object" + && value !== null + && "providerID" in value + && typeof value.providerID === "string" + && "modelID" in value + && typeof value.modelID === "string" +} + +function toMetadataModel(model: ModelLike): MetadataModel { + const metadataModel: MetadataModel = { + providerID: model.providerID, + modelID: model.modelID, + } + + if ("variant" in model && model.variant) { + metadataModel.variant = model.variant + } + + return metadataModel +} + +export function resolveMetadataModel( + primary: ModelLike | undefined, + fallback: ModelLike | undefined, +): MetadataModel | undefined { + if (isModelLike(primary)) { + return toMetadataModel(primary) + } + if (isModelLike(fallback)) { + return toMetadataModel(fallback) + } + return undefined +} diff --git a/src/tools/delegate-task/sync-continuation.test.ts b/src/tools/delegate-task/sync-continuation.test.ts index fa05e93ab..37757dbeb 100644 --- a/src/tools/delegate-task/sync-continuation.test.ts +++ b/src/tools/delegate-task/sync-continuation.test.ts @@ -86,7 +86,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -97,7 +97,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -148,7 +148,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -159,7 +159,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -214,7 +214,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -222,7 +222,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes successfully - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - toast should be removed exactly once expect(removeTaskCalls.length).toBe(1) @@ -278,7 +278,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -286,7 +286,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation with abort signal - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - removeTask should be called at least once (poller and finally may both call it) expect(removeTaskCalls.length).toBeGreaterThanOrEqual(1) @@ -335,7 +335,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "test prompt", description: "test task", load_skills: [], @@ -346,7 +346,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { let error: any = null let result: string | null = null try { - result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) } catch (e) { error = e } @@ -395,7 +395,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume oracle task", load_skills: [], @@ -403,7 +403,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes with agent info in messages - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - task_metadata should contain subagent field with the agent name expect(result).toContain("") @@ -449,7 +449,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume task", load_skills: [], @@ -457,7 +457,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - executeSyncContinuation completes without agent info - const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + const result = await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then - task_metadata should NOT contain subagent field expect(result).toContain("") @@ -514,7 +514,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue working", description: "resume explore task", load_skills: [], @@ -522,7 +522,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) @@ -584,7 +584,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue researching", description: "resume librarian task", load_skills: [], @@ -592,7 +592,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) @@ -654,7 +654,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } const args = { - session_id: "ses_test_12345678", + task_id: "ses_test_12345678", prompt: "continue planning", description: "resume prometheus task", load_skills: [], @@ -662,7 +662,7 @@ describe("executeSyncContinuation - toast cleanup error paths", () => { } //#when - await executeSyncContinuation(args, mockCtx, mockExecutorCtx, deps) + await executeSyncContinuation(args, mockCtx, mockExecutorCtx, { sessionID: "parent-session", messageID: "parent-message" }, deps) //#then expect(promptAsyncCalls).toHaveLength(1) diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index fa6f9f022..add3afd0d 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -1,28 +1,82 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" -import type { ExecutorContext, SessionMessage } from "./executor-types" +import type { ExecutorContext, ParentContext, SessionMessage } from "./executor-types" import { isPlanFamily } from "./constants" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" -import { getMessageDir } from "../../shared" +import { getMessageDir, normalizeSDKResponse } from "../../shared" import { promptWithModelSuggestionRetry } from "../../shared/model-suggestion-retry" -import { findNearestMessageWithFields } from "../../features/hook-message-injector" +import { resolveMessageContext } from "../../features/hook-message-injector" import { formatDuration } from "./time-formatter" import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps" import { setSessionTools } from "../../shared/session-tools-store" -import { normalizeSDKResponse } from "../../shared" import { buildTaskPrompt } from "./prompt-builder" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { getTaskID } from "./task-id" +import { resolveMetadataModel } from "./resolve-metadata-model" + +type ResumeModel = { providerID: string; modelID: string } + +type ResumeContext = { + resumeAgent?: string + resumeModel?: ResumeModel + resumeVariant?: string + anchorMessageCount?: number +} + +async function resolveResumeContext( + client: ExecutorContext["client"], + continuationID: string +): Promise { + try { + const messagesResp = await client.session.messages({ path: { id: continuationID } }) + const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[]) + + for (let index = messages.length - 1; index >= 0; index--) { + const info = messages[index].info + if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { + return { + resumeAgent: info.agent, + resumeModel: info.model ?? (info.providerID && info.modelID + ? { providerID: info.providerID, modelID: info.modelID } + : undefined), + resumeVariant: info.variant, + anchorMessageCount: messages.length, + } + } + } + + return { anchorMessageCount: messages.length } + } catch { + const resumeMessageDir = getMessageDir(continuationID) + const { prevMessage } = await resolveMessageContext(continuationID, client, resumeMessageDir) + const resumeMessageModel = prevMessage?.model + + return { + resumeAgent: prevMessage?.agent, + resumeModel: resumeMessageModel?.providerID && resumeMessageModel.modelID + ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } + : undefined, + resumeVariant: resumeMessageModel?.variant, + } + } +} export async function executeSyncContinuation( args: DelegateTaskArgs, ctx: ToolContextWithMetadata, executorCtx: ExecutorContext, - deps: SyncContinuationDeps = syncContinuationDeps + parentContext: ParentContext, + deps: SyncContinuationDeps = syncContinuationDeps, + systemContent?: string ): Promise { const { client, syncPollTimeoutMs, sisyphusAgentConfig } = executorCtx const toastManager = getTaskToastManager() - const taskId = `resume_sync_${args.session_id!.slice(0, 8)}` + const continuationID = getTaskID(args) + if (!continuationID) { + throw new Error("task_id is required to continue a sync task") + } + const taskId = `resume_sync_${continuationID.slice(0, 8)}` const startTime = new Date() if (toastManager) { @@ -34,55 +88,40 @@ export async function executeSyncContinuation( }) } - let syncContMeta: { title: string; metadata: Record } | undefined - let resumeAgent: string | undefined - let resumeModel: { providerID: string; modelID: string } | undefined + let resumeModel: ResumeModel | undefined let resumeVariant: string | undefined let anchorMessageCount: number | undefined try { - try { - const messagesResp = await client.session.messages({ path: { id: args.session_id! } }) - const messages = normalizeSDKResponse(messagesResp, [] as SessionMessage[]) - anchorMessageCount = messages.length - for (let i = messages.length - 1; i >= 0; i--) { - const info = messages[i].info - if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { - resumeAgent = info.agent - resumeModel = info.model ?? (info.providerID && info.modelID ? { providerID: info.providerID, modelID: info.modelID } : undefined) - resumeVariant = info.variant - break - } - } - } catch { - const resumeMessageDir = getMessageDir(args.session_id!) - const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null - resumeAgent = resumeMessage?.agent - resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID - ? { providerID: resumeMessage.model.providerID, modelID: resumeMessage.model.modelID } - : undefined - resumeVariant = resumeMessage?.model?.variant - } + const resumeContext = await resolveResumeContext(client, continuationID) + resumeAgent = resumeContext.resumeAgent + resumeModel = resumeContext.resumeModel + resumeVariant = resumeContext.resumeVariant + anchorMessageCount = resumeContext.anchorMessageCount - syncContMeta = { + const resumeModelForMetadata = resumeModel && resumeVariant !== undefined + ? { ...resumeModel, variant: resumeVariant } + : resumeModel + + const syncContMeta = { title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, + ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), + ...(args.category !== undefined ? { category: args.category } : {}), + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, - sessionId: args.session_id, + taskId: continuationID, + sessionId: continuationID, sync: true, command: args.command, - model: resumeModel, + model: resolveMetadataModel(resumeModelForMetadata, parentContext.model), }, } - await ctx.metadata?.(syncContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncContMeta) - } + await publishToolMetadata(ctx, syncContMeta) const allowTask = isPlanFamily(resumeAgent) const tddEnabled = sisyphusAgentConfig?.tdd @@ -93,14 +132,15 @@ export async function executeSyncContinuation( question: false, ...(resumeAgent ? getAgentToolRestrictions(resumeAgent) : {}), } - setSessionTools(args.session_id!, tools) + setSessionTools(continuationID, tools) await promptWithModelSuggestionRetry(client, { - path: { id: args.session_id! }, + path: { id: continuationID }, body: { ...(resumeAgent !== undefined ? { agent: resumeAgent } : {}), ...(resumeModel !== undefined ? { model: resumeModel } : {}), ...(resumeVariant !== undefined ? { variant: resumeVariant } : {}), + system: systemContent, tools, parts: [{ type: "text", text: effectivePrompt }], }, @@ -110,12 +150,12 @@ export async function executeSyncContinuation( toastManager.removeTask(taskId) } const errorMessage = promptError instanceof Error ? promptError.message : String(promptError) - return `Failed to send continuation prompt: ${errorMessage}\n\nSession ID: ${args.session_id}` + return `Failed to send continuation prompt: ${errorMessage}\n\nTask ID: ${continuationID}` } try { const pollError = await deps.pollSyncSession(ctx, client, { - sessionID: args.session_id!, + sessionID: continuationID, agentToUse: resumeAgent ?? "continue", toastManager, taskId, @@ -125,7 +165,7 @@ export async function executeSyncContinuation( return pollError } - const result = await deps.fetchSyncResult(client, args.session_id!, anchorMessageCount) + const result = await deps.fetchSyncResult(client, continuationID, anchorMessageCount) if (!result.ok) { return result.error } @@ -138,9 +178,12 @@ export async function executeSyncContinuation( ${result.textContent || "(No text output)"} - -session_id: ${args.session_id} -${resumeAgent ? `subagent: ${resumeAgent}\n` : ""}` +${buildTaskMetadataBlock({ + sessionId: continuationID, + taskId: continuationID, + agent: resumeAgent, + category: args.category, + })}` } finally { if (toastManager) { toastManager.removeTask(taskId) diff --git a/src/tools/delegate-task/sync-task.test.ts b/src/tools/delegate-task/sync-task.test.ts index 16bc31521..a81fe4eb1 100644 --- a/src/tools/delegate-task/sync-task.test.ts +++ b/src/tools/delegate-task/sync-task.test.ts @@ -272,11 +272,11 @@ describe("executeSyncTask - cleanup on error paths", () => { const initialModel = { providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", } const fallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["opencode-go"], model: "kimi-k2.5" }, ] @@ -289,7 +289,7 @@ describe("executeSyncTask - cleanup on error paths", () => { expect(result).toContain("Task completed") expect(result).toContain("Model: opencode-go/kimi-k2.5") expect(attemptedModels).toEqual([ - { providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }, + { providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }, { providerID: "opencode-go", modelID: "kimi-k2.5", variant: undefined }, ]) }) @@ -339,11 +339,11 @@ describe("executeSyncTask - cleanup on error paths", () => { const initialModel = { providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", } const fallbackChain = [ - { providers: ["anthropic"], model: "claude-opus-4-6", variant: "max" }, + { providers: ["anthropic"], model: "claude-opus-4-7", variant: "max" }, { providers: ["opencode-go"], model: "kimi-k2.5" }, { providers: ["openai"], model: "gpt-5.4", variant: "medium" }, ] @@ -356,7 +356,7 @@ describe("executeSyncTask - cleanup on error paths", () => { //#then expect(result).toBe("Final failure") expect(attemptedModels).toEqual([ - { providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }, + { providerID: "anthropic", modelID: "claude-opus-4-7", variant: "max" }, { providerID: "opencode-go", modelID: "kimi-k2.5", variant: undefined }, { providerID: "openai", modelID: "gpt-5.4", variant: "medium" }, ]) diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 18d99e500..b1a0d6f38 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -2,16 +2,16 @@ import type { ModelFallbackInfo } from "../../features/task-toast-manager/types" import type { DelegateTaskArgs, ToolContextWithMetadata, DelegatedModelConfig } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" import { getTaskToastManager } from "../../features/task-toast-manager" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { subagentSessions, syncSubagentSessions, setSessionAgent } from "../../features/claude-code-session-state" import { log } from "../../shared/logger" import { SessionCategoryRegistry } from "../../shared/session-category-registry" import { formatDuration } from "./time-formatter" import { formatDetailedError } from "./error-formatting" import { syncTaskDeps, type SyncTaskDeps } from "./sync-task-deps" -import { setSessionFallbackChain, clearSessionFallbackChain } from "../../hooks/model-fallback/hook" import { retrySyncPromptWithFallbacks } from "./sync-task-fallback" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" +import { resolveMetadataModel } from "./resolve-metadata-model" export async function executeSyncTask( args: DelegateTaskArgs, @@ -38,7 +38,7 @@ export async function executeSyncTask( spawnReservation = await manager.reserveSubagentSpawn(parentContext.sessionID) } - // Depth/descendant guard. We must NOT silently fall back to childDepth: 1 + // Depth guard. We must NOT silently fall back to childDepth: 1 // when the manager is unavailable or lacks the spawn methods, because that // would let subagents recurse without bound. The only safe fallback is // when the manager genuinely cannot enforce limits (legacy SDK), in which @@ -52,7 +52,7 @@ export async function executeSyncTask( } else { log( "[task] WARNING: BackgroundManager has no spawn enforcement methods (reserveSubagentSpawn / assertCanSpawn). " + - "Depth and descendant limits cannot be enforced for this task. This indicates an old SDK or a misconfiguration.", + "Depth limits cannot be enforced for this task. This indicates an old SDK or a misconfiguration.", { parentSessionID: parentContext.sessionID } ) spawnContext = { @@ -80,7 +80,7 @@ export async function executeSyncTask( subagentSessions.add(sessionID) syncSubagentSessions.add(sessionID) setSessionAgent(sessionID, agentToUse) - setSessionFallbackChain(sessionID, fallbackChain) + executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionID, fallbackChain) if (args.category) { SessionCategoryRegistry.register(sessionID, args.category) @@ -88,13 +88,15 @@ export async function executeSyncTask( if (onSyncSessionCreated) { log("[task] Invoking onSyncSessionCreated callback", { sessionID, parentID: parentContext.sessionID }) - await onSyncSessionCreated({ - sessionID, - parentID: parentContext.sessionID, - title: args.description, - }).catch((err) => { - log("[task] onSyncSessionCreated callback failed", { error: String(err) }) - }) + try { + await onSyncSessionCreated({ + sessionID, + parentID: parentContext.sessionID, + title: args.description, + }) + } catch (error) { + log("[task] onSyncSessionCreated callback failed", { error: String(error) }) + } await new Promise(r => setTimeout(r, 200)) } @@ -120,32 +122,34 @@ export async function executeSyncTask( prompt: args.prompt, agent: agentToUse, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, + taskId: sessionID, sessionId: sessionID, sync: true, spawnDepth: spawnContext.childDepth, command: args.command, - model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, + model: resolveMetadataModel(categoryModel, parentContext.model), }, } - await ctx.metadata?.(syncTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncTaskMeta) - } + await publishToolMetadata(ctx, syncTaskMeta) - let effectiveCategoryModel = categoryModel - let promptError = await deps.sendSyncPrompt(client, { + const syncPromptInput = { sessionID, agentToUse, args, systemContent, - categoryModel: effectiveCategoryModel, toastManager, taskId, sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, + } + + let effectiveCategoryModel = categoryModel + let promptError = await deps.sendSyncPrompt(client, { + ...syncPromptInput, + categoryModel: effectiveCategoryModel, }) if (promptError) { const promptResult = await retrySyncPromptWithFallbacks({ @@ -155,14 +159,8 @@ export async function executeSyncTask( fallbackChain, sendPrompt: async (fallbackModel) => { return deps.sendSyncPrompt(client, { - sessionID, - agentToUse, - args, - systemContent, + ...syncPromptInput, categoryModel: fallbackModel, - toastManager, - taskId, - sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, }) }, }) @@ -200,12 +198,12 @@ export async function executeSyncTask( const parentModelStr = parentContext.model ? `${parentContext.model.providerID}/${parentContext.model.modelID}` : undefined - const modelRoutingNote = - actualModelStr && parentModelStr && actualModelStr !== parentModelStr - ? `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` - : actualModelStr - ? `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` - : "" + let modelRoutingNote = "" + if (actualModelStr && parentModelStr && actualModelStr !== parentModelStr) { + modelRoutingNote = `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` + } else if (actualModelStr) { + modelRoutingNote = `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` + } return `Task completed in ${duration}. @@ -215,9 +213,12 @@ Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}${mod ${result.textContent || "(No text output)"} - -session_id: ${sessionID} -` +${buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + agent: agentToUse, + category: args.category, + })}` } finally { if (toastManager && taskId !== undefined) { toastManager.removeTask(taskId) @@ -236,7 +237,7 @@ session_id: ${sessionID} if (syncSessionID) { subagentSessions.delete(syncSessionID) syncSubagentSessions.delete(syncSessionID) - clearSessionFallbackChain(syncSessionID) + executorCtx.modelFallbackControllerAccessor?.clearSessionFallbackChain(syncSessionID) SessionCategoryRegistry.remove(syncSessionID) } } diff --git a/src/tools/delegate-task/task-id.ts b/src/tools/delegate-task/task-id.ts new file mode 100644 index 000000000..c42697898 --- /dev/null +++ b/src/tools/delegate-task/task-id.ts @@ -0,0 +1,5 @@ +import type { DelegateTaskArgs } from "./types" + +export function getTaskID(args: Pick): string | undefined { + return args.task_id +} diff --git a/src/tools/delegate-task/task-schema.test.ts b/src/tools/delegate-task/task-schema.test.ts index 0a6f1c7ee..c50d175bc 100644 --- a/src/tools/delegate-task/task-schema.test.ts +++ b/src/tools/delegate-task/task-schema.test.ts @@ -41,6 +41,7 @@ function createDelegateTask(...args: Parameters, ctx: ToolContextWithMetadata): Promise { + const category = typeof args.category === "string" ? args.category : undefined + const prompt = typeof args.prompt === "string" ? args.prompt : "" + const originalSubagentType = typeof args.subagent_type === "string" ? args.subagent_type : undefined + let subagentType = originalSubagentType + + if (category && subagentType && subagentType !== SISYPHUS_JUNIOR_AGENT) { + log("[task] category provided - overriding subagent_type to sisyphus-junior", { + category, + subagent_type: subagentType, + }) + } + + if (category) { + subagentType = SISYPHUS_JUNIOR_AGENT + } + + let description = typeof args.description === "string" ? args.description : undefined + if (!description || description.trim() === "") { + const words = prompt.trim().split(/\s+/) + description = words.slice(0, 4).join(" ") || "Delegated task" + } + + await ctx.metadata?.({ + title: description, + }) + + const runInBackground = args.run_in_background + if (runInBackground === undefined) { + throw new Error("Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.") + } + + let loadSkills = args.load_skills + if (typeof loadSkills === "string") { + try { + const parsed = JSON.parse(loadSkills) + loadSkills = Array.isArray(parsed) ? parsed : [] + } catch { + loadSkills = [] + } + } + + if (loadSkills === undefined) { + throw new Error("Invalid arguments: 'load_skills' parameter is REQUIRED. Pass [] if no skills needed.") + } + + if (loadSkills === null) { + throw new Error("Invalid arguments: load_skills=null is not allowed. Pass [] if no skills needed.") + } + + const normalizedLoadSkills = Array.isArray(loadSkills) + ? loadSkills.filter((value): value is string => typeof value === "string") + : [] + + const taskID = typeof args.task_id === "string" ? args.task_id : undefined + const command = typeof args.command === "string" ? args.command : undefined + + args.category = category + args.subagent_type = subagentType + args.requested_subagent_type = originalSubagentType + args.description = description + args.prompt = prompt + args.run_in_background = runInBackground + args.task_id = taskID + args.command = command + args.load_skills = normalizedLoadSkills + + return { + category, + subagent_type: subagentType, + requested_subagent_type: originalSubagentType, + description, + prompt, + run_in_background: runInBackground === true, + task_id: taskID, + command, + load_skills: normalizedLoadSkills, + } +} diff --git a/src/tools/delegate-task/tool-description.ts b/src/tools/delegate-task/tool-description.ts new file mode 100644 index 000000000..0b2717a82 --- /dev/null +++ b/src/tools/delegate-task/tool-description.ts @@ -0,0 +1,86 @@ +import type { AvailableCategory, AvailableSkill } from "../../agents/dynamic-agent-prompt-builder" +import { mergeCategories } from "../../shared/merge-categories" +import { CATEGORY_DESCRIPTIONS } from "./constants" +import type { DelegateTaskToolOptions } from "./types" + +export interface DelegateTaskPresentation { + availableCategories: AvailableCategory[] + availableSkills: AvailableSkill[] + categoryExamples: string + description: string +} + +export function createDelegateTaskPresentation(options: DelegateTaskToolOptions): DelegateTaskPresentation { + const { userCategories } = options + const allCategories = mergeCategories(userCategories) + const categoryEntries = Object.entries(allCategories).map(([name, categoryConfig]) => ({ + name, + categoryConfig, + description: userCategories?.[name]?.description || CATEGORY_DESCRIPTIONS[name], + })) + const categoryNames = categoryEntries.map(({ name }) => name) + const categoryExamples = categoryNames.join(", ") + + const availableCategories: AvailableCategory[] = options.availableCategories + ?? categoryEntries.map(({ name, categoryConfig, description }) => { + return { + name, + description: description || "General tasks", + model: categoryConfig.model, + } + }) + + const availableSkills: AvailableSkill[] = options.availableSkills ?? [] + + const categoryList = categoryEntries.map(({ name, description }) => { + return description ? ` - ${name}: ${description}` : ` - ${name}` + }).join("\n") + + const description = `Spawn agent task with category-based or direct agent selection. + + ⚠️ CRITICAL: You MUST provide EITHER category OR subagent_type. Omitting BOTH will FAIL. + + **COMMON MISTAKE (DO NOT DO THIS):** + \`\`\` + task(description="...", prompt="...", run_in_background=false) // ❌ FAILS - missing category AND subagent_type + \`\`\` + + **CORRECT - Using category:** + \`\`\` + task(category="quick", load_skills=[], description="Fix type error", prompt="...", run_in_background=false) + \`\`\` + + **CORRECT - Using subagent_type:** + \`\`\` + task(subagent_type="explore", load_skills=[], description="Find patterns", prompt="...", run_in_background=true) + \`\`\` + + REQUIRED: Provide ONE of: + - category: For task delegation (uses Sisyphus-Junior with category-optimized model) + - subagent_type: For direct agent invocation (explore, librarian, oracle, etc.) + + **DO NOT provide both.** If category is provided, subagent_type is ignored. + + - load_skills: ALWAYS REQUIRED. Pass [] if no skills needed, or ["skill-1", "skill-2"] for category tasks. + - category: Use predefined category → Spawns Sisyphus-Junior with category config + Available categories: + ${categoryList} + - subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus) + - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries. + - task_id: Existing task to continue (from previous task output). Continues the same subagent session with FULL CONTEXT PRESERVED. + - command: The command that triggered this task (optional, for slash command tracking). + + **WHEN TO USE task_id:** + - Task failed/incomplete → task_id with "fix: [specific issue]" + - Need follow-up on previous result → task_id with additional question + - Multi-turn conversation with same agent → always task_id instead of new task + + Prompts MUST be in English.` + + return { + availableCategories, + availableSkills, + categoryExamples, + description, + } +} diff --git a/src/tools/delegate-task/tools.test.ts b/src/tools/delegate-task/tools.test.ts index 5353ed6d5..2f703fa47 100644 --- a/src/tools/delegate-task/tools.test.ts +++ b/src/tools/delegate-task/tools.test.ts @@ -28,7 +28,7 @@ const SYSTEM_DEFAULT_MODEL = "anthropic/claude-sonnet-4-6" const TEST_CONNECTED_PROVIDERS = ["anthropic", "google", "openai"] const TEST_AVAILABLE_MODELS = new Set([ - "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", "anthropic/claude-sonnet-4-6", "anthropic/claude-haiku-4-5", "google/gemini-3.1-pro", @@ -66,7 +66,7 @@ describe("sisyphus-task", () => { cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic", "google", "openai"]) providerModelsSpy = spyOn(connectedProvidersCache, "readProviderModelsCache").mockReturnValue({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"], google: ["gemini-3.1-pro", "gemini-3-flash"], openai: ["gpt-5.4", "gpt-5.3-codex"], }, @@ -112,13 +112,13 @@ describe("sisyphus-task", () => { expect(category.variant).toBe("medium") }) - test("unspecified-high category uses claude-opus-4-6 max as primary", () => { + test("unspecified-high category uses claude-opus-4-7 max as primary", () => { // given const category = DEFAULT_CATEGORIES["unspecified-high"] // when / #then expect(category).toBeDefined() - expect(category.model).toBe("anthropic/claude-opus-4-6") + expect(category.model).toBe("anthropic/claude-opus-4-7") expect(category.variant).toBe("max") }) }) @@ -757,7 +757,7 @@ describe("sisyphus-task", () => { test("blocks requiresModel when availability is known and missing the required model", () => { // given - artistry has requiresModel: gemini-3.1-pro const categoryName = "artistry" - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) // when const result = resolveCategoryConfig(categoryName, { @@ -787,9 +787,9 @@ describe("sisyphus-task", () => { test("bypasses requiresModel when explicit user config provided", () => { // #given const categoryName = "deep" - const availableModels = new Set(["anthropic/claude-opus-4-6"]) + const availableModels = new Set(["anthropic/claude-opus-4-7"]) const userCategories = { - deep: { model: "anthropic/claude-opus-4-6" }, + deep: { model: "anthropic/claude-opus-4-7" }, } // #when @@ -801,7 +801,7 @@ describe("sisyphus-task", () => { // #then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("bypasses requiresModel when explicit user config provided even with empty availability", () => { @@ -809,7 +809,7 @@ describe("sisyphus-task", () => { const categoryName = "deep" const availableModels = new Set() const userCategories = { - deep: { model: "anthropic/claude-opus-4-6" }, + deep: { model: "anthropic/claude-opus-4-7" }, } // #when @@ -821,7 +821,7 @@ describe("sisyphus-task", () => { // #then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("returns default model from DEFAULT_CATEGORIES for builtin category", () => { @@ -841,7 +841,7 @@ describe("sisyphus-task", () => { // given const categoryName = "visual-engineering" const userCategories = { - "visual-engineering": { model: "anthropic/claude-opus-4-6" }, + "visual-engineering": { model: "anthropic/claude-opus-4-7" }, } // when @@ -849,7 +849,7 @@ describe("sisyphus-task", () => { // then expect(result).not.toBeNull() - expect(result!.config.model).toBe("anthropic/claude-opus-4-6") + expect(result!.config.model).toBe("anthropic/claude-opus-4-7") }) test("user prompt_append is appended to default", () => { @@ -913,7 +913,7 @@ describe("sisyphus-task", () => { test("category built-in model takes precedence over inheritedModel", () => { // given - builtin category with its own model, parent model also provided const categoryName = "visual-engineering" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -927,7 +927,7 @@ describe("sisyphus-task", () => { // given - custom category with no model defined const categoryName = "my-custom-no-model" const userCategories = { "my-custom-no-model": { temperature: 0.5 } } as unknown as Record - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -943,7 +943,7 @@ describe("sisyphus-task", () => { const userCategories = { "visual-engineering": { model: "my-provider/my-model" }, } - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const result = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -1054,7 +1054,7 @@ describe("sisyphus-task", () => { const mockClient = { app: { agents: async () => ({ data: [] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, - model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] }, + model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] }, session: { create: async () => ({ data: { id: "test-session" } }), prompt: async () => ({ data: {} }), @@ -1078,7 +1078,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES + // when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high default variant", @@ -1090,10 +1090,10 @@ describe("sisyphus-task", () => { toolContext ) - // then - claude-opus-4-6 should be passed with max variant + // then - claude-opus-4-7 should be passed with max variant expect(launchInput.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", variant: "max", }) }, { timeout: 20000 }) @@ -1113,7 +1113,7 @@ describe("sisyphus-task", () => { const mockClient = { app: { agents: async () => ({ data: [] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, - model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-6" }] }, + model: { list: async () => [{ provider: "anthropic", id: "claude-opus-4-7" }] }, session: { get: async () => ({ data: { directory: "/project" } }), create: async () => ({ data: { id: "ses_sync_default_variant" } }), @@ -1139,7 +1139,7 @@ describe("sisyphus-task", () => { abort: new AbortController().signal, } - // when - unspecified-high uses claude-opus-4-6 max in DEFAULT_CATEGORIES + // when - unspecified-high uses claude-opus-4-7 max in DEFAULT_CATEGORIES await tool.execute( { description: "Test unspecified-high sync variant", @@ -1151,10 +1151,10 @@ describe("sisyphus-task", () => { toolContext ) - // then - claude-opus-4-6 should be passed with max variant + // then - claude-opus-4-7 should be passed with max variant expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) expect(promptBody.variant).toBe("max") }, { timeout: 20000 }) @@ -1359,7 +1359,7 @@ describe("sisyphus-task", () => { )).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED") }) - test("#given session_id without run_in_background #when executing #then throws required parameter error", async () => { + test("#given task_id without run_in_background #when executing #then throws required parameter error", async () => { // given const { createDelegateTask } = require("./tools") const mockManager = { resume: async () => ({ id: "task-1", sessionID: "ses_1", status: "running" }) } @@ -1381,14 +1381,14 @@ describe("sisyphus-task", () => { { description: "Continue without run flag", prompt: "Continue", - session_id: "ses_existing", + task_id: "ses_existing", load_skills: [], }, { sessionID: "parent-session", messageID: "parent-message", agent: "sisyphus", abort: new AbortController().signal } )).rejects.toThrow("Invalid arguments: 'run_in_background' parameter is REQUIRED") }) - test("#given no category no subagent_type no session_id and no run_in_background #when executing #then throws required parameter error", async () => { + test("#given no category no subagent_type no task_id and no run_in_background #when executing #then throws required parameter error", async () => { // given const { createDelegateTask } = require("./tools") const mockManager = { launch: async () => ({}) } @@ -1550,7 +1550,7 @@ describe("sisyphus-task", () => { let promptCalled = false const mockManager = { launch: async () => ({}) } const mockClient = { - app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }] }) }, + app: { agents: async () => ({ data: [{ name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } }] }) }, config: { get: async () => ({ data: { model: SYSTEM_DEFAULT_MODEL } }) }, session: { get: async () => ({ data: { directory: "/project" } }), @@ -1719,8 +1719,8 @@ describe("sisyphus-task", () => { }, { timeout: 10000 }) }) - describe("session_id with background parameter", () => { - test("session_id with background=false should wait for result and return content", async () => { + describe("task_id with background parameter", () => { + test("task_id with background=false should wait for result and return content", async () => { // Note: This test needs extended timeout because the implementation has MIN_STABILITY_TIME_MS = 5000 // given const { createDelegateTask } = require("./tools") @@ -1808,7 +1808,7 @@ describe("sisyphus-task", () => { { description: "Continue test", prompt: "Continue the task", - session_id: "ses_continue_test", + task_id: "ses_continue_test", run_in_background: false, load_skills: ["git-master"], }, @@ -1835,7 +1835,7 @@ describe("sisyphus-task", () => { id: "msg_001", role: "user", agent: "sisyphus-junior", - model: { providerID: "anthropic", modelID: "claude-opus-4-6" }, + model: { providerID: "anthropic", modelID: "claude-opus-4-7" }, variant: "max", time: { created: baseTime }, }, @@ -1905,7 +1905,7 @@ describe("sisyphus-task", () => { { description: "Continue with variant", prompt: "Continue the task", - session_id: "ses_var_test", + task_id: "ses_var_test", run_in_background: false, load_skills: [], }, @@ -1917,10 +1917,10 @@ describe("sisyphus-task", () => { const callArgs = promptMock.mock.calls[0][0] expect(callArgs.body.variant).toBe("max") expect(callArgs.body.agent).toBe("sisyphus-junior") - expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6" }) + expect(callArgs.body.model).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-7" }) }, { timeout: 10000 }) - test("session_id with background=true should return immediately without waiting", async () => { + test("task_id with background=true should return immediately without waiting", async () => { // given const { createDelegateTask } = require("./tools") @@ -1964,7 +1964,7 @@ describe("sisyphus-task", () => { { description: "Continue bg test", prompt: "Continue in background", - session_id: "ses_bg_continue", + task_id: "ses_bg_continue", run_in_background: true, load_skills: ["git-master"], }, @@ -2551,7 +2551,7 @@ describe("sisyphus-task", () => { // Override provider cache to include kimi-for-coding provider providerModelsSpy.mockReturnValue({ models: { - anthropic: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"], + anthropic: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"], google: ["gemini-3.1-pro", "gemini-3-flash"], openai: ["gpt-5.4", "gpt-5.3-codex"], "kimi-for-coding": ["k2p5"], @@ -2798,7 +2798,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, userCategories: { - "fallback-test": { model: "anthropic/claude-opus-4-6" }, + "fallback-test": { model: "anthropic/claude-opus-4-7" }, }, connectedProvidersOverride: TEST_CONNECTED_PROVIDERS, availableModelsOverride: createTestAvailableModels(), @@ -3465,7 +3465,7 @@ describe("sisyphus-task", () => { test("category built-in model takes precedence over inheritedModel for builtin category", () => { // given - builtin ultrabrain category with its own model, inherited model also provided const categoryName = "ultrabrain" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3480,7 +3480,7 @@ describe("sisyphus-task", () => { // given const categoryName = "ultrabrain" const userCategories = { "ultrabrain": { model: "my-provider/custom-model" } } - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" // when const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3497,7 +3497,7 @@ describe("sisyphus-task", () => { // given - This test verifies the fix for PR #770 bug // The bug was: checking `if (inheritedModel)` instead of `if (actualModel === inheritedModel)` const categoryName = "ultrabrain" - const inheritedModel = "cliproxy/claude-opus-4-6" + const inheritedModel = "cliproxy/claude-opus-4-7" const userCategories = { "ultrabrain": { model: "user/model" } } // when - user model wins @@ -3525,7 +3525,7 @@ describe("sisyphus-task", () => { // given a builtin category with its own model, and an inherited model from parent // The CORRECT chain: userConfig?.model ?? categoryBuiltIn ?? systemDefaultModel const categoryName = "ultrabrain" - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when category has a built-in model (gpt-5.4 for ultrabrain) const resolved = resolveCategoryConfig(categoryName, { inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3556,7 +3556,7 @@ describe("sisyphus-task", () => { // given userConfig.model is explicitly set const categoryName = "ultrabrain" const userCategories = { "ultrabrain": { model: "custom/user-model" } } - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" const systemDefaultModel = "anthropic/claude-sonnet-4-6" // when resolveCategoryConfig is called with all sources @@ -3575,7 +3575,7 @@ describe("sisyphus-task", () => { // given userConfig.model is empty string "" for a custom category (no built-in model) const categoryName = "custom-empty-model" const userCategories = { "custom-empty-model": { model: "", temperature: 0.3 } } - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when resolveCategoryConfig is called const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3590,7 +3590,7 @@ describe("sisyphus-task", () => { const categoryName = "visual-engineering" // Using type assertion since we're testing fallback behavior for categories without model const userCategories = { "visual-engineering": { temperature: 0.2 } } as unknown as Record - const inheritedModel = "anthropic/claude-opus-4-6" + const inheritedModel = "anthropic/claude-opus-4-7" // when resolveCategoryConfig is called const resolved = resolveCategoryConfig(categoryName, { userCategories, inheritedModel, systemDefaultModel: SYSTEM_DEFAULT_MODEL }) @@ -3810,7 +3810,7 @@ describe("sisyphus-task", () => { app: { agents: async () => ({ data: [ - { name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-6" } }, + { name: "oracle", mode: "subagent", model: { providerID: "anthropic", modelID: "claude-opus-4-7" } }, ], }), }, @@ -3854,7 +3854,7 @@ describe("sisyphus-task", () => { // then - matched agent's model should be passed to session.prompt expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }, { timeout: 20000 }) @@ -3956,7 +3956,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, agentOverrides: { - oracle: { model: "anthropic/claude-opus-4-6" }, + oracle: { model: "anthropic/claude-opus-4-7" }, }, }) @@ -3982,7 +3982,7 @@ describe("sisyphus-task", () => { // then - user-configured model should take priority over matchedAgent.model expect(promptBody.model).toEqual({ providerID: "anthropic", - modelID: "claude-opus-4-6", + modelID: "claude-opus-4-7", }) }, { timeout: 20000 }) @@ -4023,7 +4023,7 @@ describe("sisyphus-task", () => { manager: mockManager, client: mockClient, agentOverrides: { - oracle: { model: "anthropic/claude-opus-4-6", variant: "max" }, + oracle: { model: "anthropic/claude-opus-4-7", variant: "max" }, }, }) @@ -4111,7 +4111,7 @@ describe("sisyphus-task", () => { ) // then - should resolve via AGENT_MODEL_REQUIREMENTS fallback chain for oracle - // oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-6 (anthropic) + // oracle fallback chain: gpt-5.4 (openai) > gemini-3.1-pro (google) > claude-opus-4-7 (anthropic) // Since openai is in connectedProviders, should resolve to openai/gpt-5.4 expect(promptBody.model).toBeDefined() expect(promptBody.model.providerID).toBe("openai") diff --git a/src/tools/delegate-task/tools.ts b/src/tools/delegate-task/tools.ts index ab55e1789..268c455ca 100644 --- a/src/tools/delegate-task/tools.ts +++ b/src/tools/delegate-task/tools.ts @@ -1,14 +1,7 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" -import type { DelegateTaskArgs, DelegatedModelConfig, ToolContextWithMetadata, DelegateTaskToolOptions } from "./types" -import { CATEGORY_DESCRIPTIONS } from "./constants" -import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" -import { mergeCategories } from "../../shared/merge-categories" +import type { DelegatedModelConfig, ToolContextWithMetadata, DelegateTaskToolOptions } from "./types" import { log } from "../../shared/logger" import { buildSystemContent } from "./prompt-builder" -import type { - AvailableCategory, - AvailableSkill, -} from "../../agents/dynamic-agent-prompt-builder" import { resolveSkillContent, resolveParentContext, @@ -20,133 +13,37 @@ import { executeBackgroundTask, executeSyncTask, } from "./executor" +import { prepareDelegateTaskArgs } from "./tool-argument-preparation" +import { createDelegateTaskPresentation } from "./tool-description" export { resolveCategoryConfig } from "./categories" export type { SyncSessionCreatedEvent, DelegateTaskToolOptions, BuildSystemContentInput } from "./types" export { buildSystemContent, buildTaskPrompt } from "./prompt-builder" +const delegateTaskArgsSchema = { + load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."), + description: tool.schema.string().optional().describe("Short task description (3-5 words). Auto-generated from prompt if omitted."), + prompt: tool.schema.string().describe("Full detailed prompt for the agent"), + run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."), + category: tool.schema.string().optional().describe("REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type."), + subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."), + task_id: tool.schema.string().optional().describe("Existing task to continue. Canonical resume identifier."), + command: tool.schema.string().optional().describe("The command that triggered this task"), +} + export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefinition { - const { userCategories } = options - - const allCategories = mergeCategories(userCategories) - const categoryNames = Object.keys(allCategories) - const categoryExamples = categoryNames.join(", ") - - const availableCategories: AvailableCategory[] = options.availableCategories - ?? Object.entries(allCategories).map(([name, categoryConfig]) => { - const userDesc = userCategories?.[name]?.description - const builtinDesc = CATEGORY_DESCRIPTIONS[name] - const description = userDesc || builtinDesc || "General tasks" - return { - name, - description, - model: categoryConfig.model, - } - }) - - const availableSkills: AvailableSkill[] = options.availableSkills ?? [] - - const categoryList = categoryNames.map(name => { - const userDesc = userCategories?.[name]?.description - const builtinDesc = CATEGORY_DESCRIPTIONS[name] - const desc = userDesc || builtinDesc - return desc ? ` - ${name}: ${desc}` : ` - ${name}` - }).join("\n") - - const description = `Spawn agent task with category-based or direct agent selection. - - ⚠️ CRITICAL: You MUST provide EITHER category OR subagent_type. Omitting BOTH will FAIL. - - **COMMON MISTAKE (DO NOT DO THIS):** - \`\`\` - task(description="...", prompt="...", run_in_background=false) // ❌ FAILS - missing category AND subagent_type - \`\`\` - - **CORRECT - Using category:** - \`\`\` - task(category="quick", load_skills=[], description="Fix type error", prompt="...", run_in_background=false) - \`\`\` - - **CORRECT - Using subagent_type:** - \`\`\` - task(subagent_type="explore", load_skills=[], description="Find patterns", prompt="...", run_in_background=true) - \`\`\` - - REQUIRED: Provide ONE of: - - category: For task delegation (uses Sisyphus-Junior with category-optimized model) - - subagent_type: For direct agent invocation (explore, librarian, oracle, etc.) - - **DO NOT provide both.** If category is provided, subagent_type is ignored. - - - load_skills: ALWAYS REQUIRED. Pass [] if no skills needed, or ["skill-1", "skill-2"] for category tasks. - - category: Use predefined category → Spawns Sisyphus-Junior with category config - Available categories: - ${categoryList} - - subagent_type: Use specific agent directly (explore, librarian, oracle, metis, momus) - - run_in_background: REQUIRED. true=async (returns task_id), false=sync (waits). Use background=true ONLY for parallel exploration with 5+ independent queries. - - session_id: Existing Task session to continue (from previous task output). Continues agent with FULL CONTEXT PRESERVED - saves tokens, maintains continuity. - - command: The command that triggered this task (optional, for slash command tracking). - - **WHEN TO USE session_id:** - - Task failed/incomplete → session_id with "fix: [specific issue]" - - Need follow-up on previous result → session_id with additional question - - Multi-turn conversation with same agent → always session_id instead of new task - - Prompts MUST be in English.` + const { availableCategories, availableSkills, categoryExamples, description } = createDelegateTaskPresentation(options) return tool({ description, - args: { - load_skills: tool.schema.array(tool.schema.string()).describe("Skill names to inject. REQUIRED - pass [] if no skills needed."), - description: tool.schema.string().optional().describe("Short task description (3-5 words). Auto-generated from prompt if omitted."), - prompt: tool.schema.string().describe("Full detailed prompt for the agent"), - run_in_background: tool.schema.boolean().describe("REQUIRED. true=async (returns task_id), false=sync (waits). Use false for task delegation, true ONLY for parallel exploration."), - category: tool.schema.string().optional().describe(`REQUIRED if subagent_type not provided. Do NOT provide both category and subagent_type.`), - subagent_type: tool.schema.string().optional().describe("REQUIRED if category not provided. Do NOT provide both category and subagent_type."), - session_id: tool.schema.string().optional().describe("Existing Task session to continue"), - command: tool.schema.string().optional().describe("The command that triggered this task"), - }, - async execute(args: DelegateTaskArgs, toolContext) { + args: delegateTaskArgsSchema, + async execute(args, toolContext) { const ctx = toolContext as ToolContextWithMetadata + const delegateTaskArgs = await prepareDelegateTaskArgs(args, ctx) - if (args.category) { - if (args.subagent_type && args.subagent_type !== SISYPHUS_JUNIOR_AGENT) { - log("[task] category provided - overriding subagent_type to sisyphus-junior", { - category: args.category, - subagent_type: args.subagent_type, - }) - } - args.subagent_type = SISYPHUS_JUNIOR_AGENT - } - // Auto-generate description from prompt when missing or empty - if (!args.description || typeof args.description !== "string" || args.description.trim() === "") { - const words = (args.prompt || "").trim().split(/\s+/) - args.description = words.slice(0, 4).join(" ") || "Delegated task" - } - await ctx.metadata?.({ - title: args.description, - }) - if (args.run_in_background === undefined) { - throw new Error(`Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.`) - } - if (typeof args.load_skills === "string") { - try { - const parsed = JSON.parse(args.load_skills) - args.load_skills = Array.isArray(parsed) ? parsed : [] - } catch { - args.load_skills = [] - } - } - if (args.load_skills === undefined) { - throw new Error(`Invalid arguments: 'load_skills' parameter is REQUIRED. Pass [] if no skills needed.`) - } - if (args.load_skills === null) { - throw new Error(`Invalid arguments: load_skills=null is not allowed. Pass [] if no skills needed.`) - } + const runInBackground = delegateTaskArgs.run_in_background === true - const runInBackground = args.run_in_background === true - - const { content: skillContent, contents: skillContents, error: skillError } = await resolveSkillContent(args.load_skills, { + const { content: skillContent, contents: skillContents, error: skillError } = await resolveSkillContent(delegateTaskArgs.load_skills, { gitMasterConfig: options.gitMasterConfig, browserProvider: options.browserProvider, disabledSkills: options.disabledSkills, @@ -156,16 +53,23 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini return skillError } + const continuationSystemContent = buildSystemContent({ + skillContent, + skillContents, + availableCategories, + availableSkills, + }) + const parentContext = await resolveParentContext(ctx, options.client) - if (args.session_id) { + if (delegateTaskArgs.task_id) { if (runInBackground) { - return executeBackgroundContinuation(args, ctx, options, parentContext) + return executeBackgroundContinuation(delegateTaskArgs, ctx, options, parentContext, continuationSystemContent) } - return executeSyncContinuation(args, ctx, options) + return executeSyncContinuation(delegateTaskArgs, ctx, options, parentContext, undefined, continuationSystemContent) } - if (!args.category && !args.subagent_type) { + if (!delegateTaskArgs.category && !delegateTaskArgs.subagent_type) { return `Invalid arguments: Must provide either category or subagent_type.` } @@ -190,8 +94,8 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini let fallbackChain: import("../../shared/model-requirements").FallbackEntry[] | undefined let maxPromptTokens: number | undefined - if (args.category) { - const resolution = await resolveCategoryExecution(args, options, inheritedModel, systemDefaultModel) + if (delegateTaskArgs.category) { + const resolution = await resolveCategoryExecution(delegateTaskArgs, options, inheritedModel, systemDefaultModel) if (resolution.error) { return resolution.error } @@ -204,14 +108,14 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini fallbackChain = resolution.fallbackChain maxPromptTokens = resolution.maxPromptTokens - const isRunInBackgroundExplicitlyFalse = args.run_in_background === false || args.run_in_background === "false" as unknown as boolean + const isRunInBackgroundExplicitlyFalse = isExplicitSyncRun(delegateTaskArgs.run_in_background) log("[task] unstable agent detection", { - category: args.category, + category: delegateTaskArgs.category, actualModel, isUnstableAgent, - run_in_background_value: args.run_in_background, - run_in_background_type: typeof args.run_in_background, + run_in_background_value: delegateTaskArgs.run_in_background, + run_in_background_type: typeof delegateTaskArgs.run_in_background, isRunInBackgroundExplicitlyFalse, willForceBackground: isUnstableAgent && isRunInBackgroundExplicitlyFalse, }) @@ -227,10 +131,10 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini availableCategories, availableSkills, }) - return executeUnstableAgentTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, actualModel) + return executeUnstableAgentTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, actualModel) } } else { - const resolution = await resolveSubagentExecution(args, options, parentContext.agent, categoryExamples) + const resolution = await resolveSubagentExecution(delegateTaskArgs, options, parentContext.agent, categoryExamples) if (resolution.error) { return resolution.error } @@ -251,10 +155,14 @@ export function createDelegateTask(options: DelegateTaskToolOptions): ToolDefini }) if (runInBackground) { - return executeBackgroundTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, fallbackChain) + return executeBackgroundTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, fallbackChain) } - return executeSyncTask(args, ctx, options, parentContext, agentToUse, categoryModel, systemContent, modelInfo, fallbackChain) + return executeSyncTask(delegateTaskArgs, ctx, options, parentContext, agentToUse, categoryModel, systemContent, modelInfo, fallbackChain) }, }) } + +function isExplicitSyncRun(runInBackground: unknown): boolean { + return runInBackground === false || runInBackground === "false" +} diff --git a/src/tools/delegate-task/types.ts b/src/tools/delegate-task/types.ts index bbb0e8e21..1eb767960 100644 --- a/src/tools/delegate-task/types.ts +++ b/src/tools/delegate-task/types.ts @@ -1,6 +1,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import type { BackgroundManager } from "../../features/background-agent" import type { CategoriesConfig, GitMasterConfig, BrowserAutomationProvider, AgentOverrides, SisyphusAgentConfig } from "../../config/schema" +import type { ModelFallbackControllerAccessor } from "../../hooks/model-fallback" import type { AvailableCategory, AvailableSkill, @@ -13,14 +14,11 @@ export interface DelegateTaskArgs { prompt: string category?: string subagent_type?: string + requested_subagent_type?: string run_in_background: boolean - session_id?: string + task_id?: string command?: string load_skills: string[] - execute?: { - task_id: string - task_dir?: string - } } export interface ToolContextWithMetadata { @@ -68,6 +66,7 @@ export interface DelegateTaskToolOptions { availableSkills?: AvailableSkill[] agentOverrides?: AgentOverrides sisyphusAgentConfig?: SisyphusAgentConfig + modelFallbackControllerAccessor?: ModelFallbackControllerAccessor onSyncSessionCreated?: (event: SyncSessionCreatedEvent) => Promise syncPollTimeoutMs?: number } diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index 7d10780cb..f81eb9971 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -3,13 +3,14 @@ import type { ExecutorContext, ParentContext, SessionMessage } from "./executor- import { DEFAULT_SYNC_POLL_TIMEOUT_MS, getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" import { cancelUnstableAgentTask } from "./cancel-unstable-agent-task" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDuration } from "./time-formatter" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { normalizeSDKResponse } from "../../shared" import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied-session-permission" +import { resolveMetadataModel } from "./resolve-metadata-model" +import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" export async function executeUnstableAgentTask( args: DelegateTaskArgs, @@ -73,19 +74,26 @@ export async function executeUnstableAgentTask( prompt: args.prompt, agent: agentToUse, category: args.category, + ...(args.requested_subagent_type !== undefined ? { requested_subagent_type: args.requested_subagent_type } : {}), load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, + taskId: sessionID, + backgroundTaskId: task.id, sessionId: sessionID, command: args.command, - model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, + model: resolveMetadataModel(categoryModel, parentContext.model), }, } - await ctx.metadata?.(bgTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgTaskMeta) - } + await publishToolMetadata(ctx, bgTaskMeta) + + const taskMetadataBlock = buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + }) const startTime = new Date() const timingCfg = getTimingConfig() @@ -152,9 +160,7 @@ Model: ${actualModel} The task session may contain partial results. - -session_id: ${sessionID} -` +${taskMetadataBlock}` } if (!completedDuringMonitoring) { @@ -172,9 +178,7 @@ Model: ${actualModel} The task session may still contain partial results. - -session_id: ${sessionID} -` +${taskMetadataBlock}` } const messagesResult = await client.session.messages({ path: { id: sessionID } }) @@ -185,9 +189,8 @@ session_id: ${sessionID} const assistantMessages = messages .filter((m) => m.info?.role === "assistant") .sort((a, b) => (b.info?.time?.created ?? 0) - (a.info?.time?.created ?? 0)) - const lastMessage = assistantMessages[0] - if (!lastMessage) { + if (assistantMessages.length === 0) { return `No assistant response found (task ran in background mode).\n\nSession ID: ${sessionID}` } @@ -222,9 +225,7 @@ RESULT: ${textContent || "(No text output)"} - -session_id: ${sessionID} -` +${taskMetadataBlock}` } catch (error) { if (!cleanupReason) { cleanupReason = "exception" diff --git a/src/tools/glob/constants.ts b/src/tools/glob/constants.ts index 05b5f85f1..8284b3681 100644 --- a/src/tools/glob/constants.ts +++ b/src/tools/glob/constants.ts @@ -1,4 +1,4 @@ -export { resolveGrepCli, resolveGrepCliWithAutoInstall, type GrepBackend, DEFAULT_RG_THREADS } from "../grep/constants" +export { resolveGrepCli, resolveGrepCliWithAutoInstall, type GrepBackend, DEFAULT_RG_THREADS } from "../../shared/ripgrep-cli" export const DEFAULT_TIMEOUT_MS = 60_000 export const DEFAULT_LIMIT = 100 diff --git a/src/tools/grep/cli.ts b/src/tools/grep/cli.ts index bcec98aaa..9f55b1d27 100644 --- a/src/tools/grep/cli.ts +++ b/src/tools/grep/cli.ts @@ -3,13 +3,15 @@ import { resolveGrepCli, type ResolvedCli, type GrepBackend, + DEFAULT_RG_THREADS, +} from "../../shared/ripgrep-cli" +import { DEFAULT_MAX_DEPTH, DEFAULT_MAX_FILESIZE, DEFAULT_MAX_COUNT, DEFAULT_MAX_COLUMNS, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_OUTPUT_BYTES, - DEFAULT_RG_THREADS, RG_SAFETY_FLAGS, GREP_SAFETY_FLAGS, } from "./constants" diff --git a/src/tools/grep/constants.ts b/src/tools/grep/constants.ts index 79db24c6b..f6c913303 100644 --- a/src/tools/grep/constants.ts +++ b/src/tools/grep/constants.ts @@ -1,126 +1,3 @@ -import { existsSync } from "node:fs" -import { join, dirname } from "node:path" -import { spawnSync } from "node:child_process" -import { getInstalledRipgrepPath, downloadAndInstallRipgrep } from "./downloader" -import { getDataDir } from "../../shared/data-path" -import { log } from "../../shared/logger" -import { PUBLISHED_PACKAGE_NAME } from "../../shared/plugin-identity" - -export type GrepBackend = "rg" | "grep" - -export interface ResolvedCli { - path: string - backend: GrepBackend -} - -let cachedCli: ResolvedCli | null = null -let autoInstallAttempted = false - -function findExecutable(name: string): string | null { - const isWindows = process.platform === "win32" - const cmd = isWindows ? "where" : "which" - - try { - const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 }) - if (result.status === 0 && result.stdout.trim()) { - return result.stdout.trim().split("\n")[0] - } - } catch { - // Command execution failed - } - return null -} - -function getOpenCodeBundledRg(): string | null { - const execPath = process.execPath - const execDir = dirname(execPath) - - const isWindows = process.platform === "win32" - const rgName = isWindows ? "rg.exe" : "rg" - - const candidates = [ - // OpenCode XDG data path (highest priority - where OpenCode installs rg) - join(getDataDir(), "opencode", "bin", rgName), - // Legacy paths relative to execPath - join(execDir, rgName), - join(execDir, "bin", rgName), - join(execDir, "..", "bin", rgName), - join(execDir, "..", "libexec", rgName), - ] - - for (const candidate of candidates) { - if (existsSync(candidate)) { - return candidate - } - } - - return null -} - -export function resolveGrepCli(): ResolvedCli { - if (cachedCli) return cachedCli - - const bundledRg = getOpenCodeBundledRg() - if (bundledRg) { - cachedCli = { path: bundledRg, backend: "rg" } - return cachedCli - } - - const systemRg = findExecutable("rg") - if (systemRg) { - cachedCli = { path: systemRg, backend: "rg" } - return cachedCli - } - - const installedRg = getInstalledRipgrepPath() - if (installedRg) { - cachedCli = { path: installedRg, backend: "rg" } - return cachedCli - } - - const grep = findExecutable("grep") - if (grep) { - cachedCli = { path: grep, backend: "grep" } - return cachedCli - } - - cachedCli = { path: "rg", backend: "rg" } - return cachedCli -} - -export async function resolveGrepCliWithAutoInstall(): Promise { - const current = resolveGrepCli() - - if (current.backend === "rg" && current.path !== "rg") { - return current - } - - if (autoInstallAttempted) { - return current - } - - autoInstallAttempted = true - - try { - const rgPath = await downloadAndInstallRipgrep() - cachedCli = { path: rgPath, backend: "rg" } - return cachedCli - } catch (error) { - if (current.backend === "grep") { - log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep. Falling back to GNU grep.`, { - error: error instanceof Error ? error.message : String(error), - grep_path: current.path, - }) - } else { - log(`[${PUBLISHED_PACKAGE_NAME}] Failed to auto-install ripgrep and GNU grep was not found.`, { - error: error instanceof Error ? error.message : String(error), - }) - } - - return current - } -} - export const DEFAULT_MAX_DEPTH = 20 export const DEFAULT_MAX_FILESIZE = "10M" export const DEFAULT_MAX_COUNT = 500 @@ -128,7 +5,6 @@ export const DEFAULT_MAX_COLUMNS = 1000 export const DEFAULT_CONTEXT = 2 export const DEFAULT_TIMEOUT_MS = 60_000 export const DEFAULT_MAX_OUTPUT_BYTES = 256 * 1024 -export const DEFAULT_RG_THREADS = 4 export const RG_SAFETY_FLAGS = [ "--no-follow", diff --git a/src/tools/grep/tools.ts b/src/tools/grep/tools.ts index eaf8a3972..c40193c56 100644 --- a/src/tools/grep/tools.ts +++ b/src/tools/grep/tools.ts @@ -1,8 +1,8 @@ import { resolve } from "node:path" import type { PluginInput } from "@opencode-ai/plugin" import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool" +import { resolveGrepCliWithAutoInstall } from "../../shared/ripgrep-cli" import { runRg, runRgCount } from "./cli" -import { resolveGrepCliWithAutoInstall } from "./constants" import { formatGrepResult, formatCountResult } from "./result-formatter" export function createGrepTools(ctx: PluginInput): Record { diff --git a/src/tools/hashline-edit/hashline-edit-executor.ts b/src/tools/hashline-edit/hashline-edit-executor.ts index b9412d89e..54509ab6c 100644 --- a/src/tools/hashline-edit/hashline-edit-executor.ts +++ b/src/tools/hashline-edit/hashline-edit-executor.ts @@ -1,5 +1,5 @@ import type { ToolContext } from "@opencode-ai/plugin/tool" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { applyHashlineEditsWithReport } from "./edit-operations" import { countLineDiffs, generateUnifiedDiff } from "./diff-utils" import { canonicalizeFileText, restoreFileText } from "./file-text-canonicalization" @@ -26,13 +26,6 @@ type ToolContextWithMetadata = ToolContextWithCallID & { metadata?: (value: unknown) => void } -function resolveToolCallID(ctx: ToolContextWithCallID): string | undefined { - if (typeof ctx.callID === "string" && ctx.callID.trim() !== "") return ctx.callID - if (typeof ctx.callId === "string" && ctx.callId.trim() !== "") return ctx.callId - if (typeof ctx.call_id === "string" && ctx.call_id.trim() !== "") return ctx.call_id - return undefined -} - function canCreateFromMissingFile(edits: HashlineEdit[]): boolean { if (edits.length === 0) return false return edits.every((edit) => (edit.op === "append" || edit.op === "prepend") && !edit.pos) @@ -143,13 +136,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.noopEdits, applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(formattedMeta) - } - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, formattedMeta) - } + await publishToolMetadata(metadataContext, formattedMeta) if (rename && rename !== filePath) { await Bun.write(rename, formattedContent) await Bun.file(filePath).delete() @@ -173,14 +160,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(meta) - } - - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, meta) - } + await publishToolMetadata(metadataContext, meta) if (rename && rename !== filePath) { return `Moved ${filePath} to ${rename}` diff --git a/src/tools/look-at/look-at-input-preparer.ts b/src/tools/look-at/look-at-input-preparer.ts new file mode 100644 index 000000000..4901eb00f --- /dev/null +++ b/src/tools/look-at/look-at-input-preparer.ts @@ -0,0 +1,151 @@ +import { basename } from "node:path" +import { pathToFileURL } from "node:url" +import type { LookAtArgs } from "./types" +import { + extractBase64Data, + inferMimeTypeFromBase64, + inferMimeTypeFromFilePath, +} from "./mime-type-inference" +import { + needsConversion, + convertImageToJpeg, + convertBase64ImageToJpeg, + cleanupConvertedImage, +} from "./image-converter" +import { log } from "../../shared" + +export interface LookAtFilePart { + type: "file" + mime: string + url: string + filename: string +} + +export interface PreparedLookAtInput { + readonly filePart: LookAtFilePart + readonly isBase64Input: boolean + readonly sourceDescription: string + cleanup(): void +} + +type PrepareLookAtInputResult = + | { ok: true; value: PreparedLookAtInput } + | { ok: false; error: string } + +function getTemporaryConversionPath(error: unknown): string | null { + if (!(error instanceof Error)) { + return null + } + + const temporaryOutputPath = Reflect.get(error, "temporaryOutputPath") + if (typeof temporaryOutputPath === "string" && temporaryOutputPath.length > 0) { + return temporaryOutputPath + } + + const temporaryDirectory = Reflect.get(error, "temporaryDirectory") + if (typeof temporaryDirectory === "string" && temporaryDirectory.length > 0) { + return temporaryDirectory + } + + return null +} + +export function prepareLookAtInput(args: LookAtArgs): PrepareLookAtInputResult { + const imageData = args.image_data + const filePath = args.file_path + + if (imageData) { + const mimeType = inferMimeTypeFromBase64(imageData) + + let finalBase64Data = extractBase64Data(imageData) + let finalMimeType = mimeType + let tempFilesToCleanup: string[] = [] + + if (needsConversion(mimeType)) { + log(`[look_at] Detected unsupported Base64 format: ${mimeType}, converting to JPEG...`) + try { + const { base64, tempFiles } = convertBase64ImageToJpeg(finalBase64Data, mimeType) + finalBase64Data = base64 + finalMimeType = "image/jpeg" + tempFilesToCleanup = tempFiles + log("[look_at] Base64 conversion successful") + } catch (conversionError) { + log(`[look_at] Base64 conversion failed: ${conversionError}`) + return { + ok: false, + error: `Error: Failed to convert Base64 image format. ${conversionError}`, + } + } + } + + return { + ok: true, + value: { + isBase64Input: true, + sourceDescription: "clipboard/pasted image", + filePart: { + type: "file", + mime: finalMimeType, + url: `data:${finalMimeType};base64,${finalBase64Data}`, + filename: `clipboard-image.${finalMimeType.split("/")[1] || "png"}`, + }, + cleanup() { + for (const temporaryFile of tempFilesToCleanup) { + cleanupConvertedImage(temporaryFile) + } + }, + }, + } + } + + if (filePath) { + let mimeType = inferMimeTypeFromFilePath(filePath) + let actualFilePath = filePath + let tempConversionPath: string | null = null + + if (needsConversion(mimeType)) { + log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`) + try { + const convertedFilePath = convertImageToJpeg(filePath, mimeType) + tempConversionPath = convertedFilePath + actualFilePath = convertedFilePath + mimeType = "image/jpeg" + log(`[look_at] Conversion successful: ${convertedFilePath}`) + } catch (conversionError) { + const failedConversionPath = getTemporaryConversionPath(conversionError) + if (failedConversionPath) { + tempConversionPath = failedConversionPath + } + log(`[look_at] Conversion failed: ${conversionError}`) + return { + ok: false, + error: `Error: Failed to convert image format. ${conversionError}`, + } + } + } + + return { + ok: true, + value: { + isBase64Input: false, + sourceDescription: filePath, + filePart: { + type: "file", + mime: mimeType, + url: pathToFileURL(actualFilePath).href, + filename: basename(actualFilePath), + }, + cleanup() { + if (tempConversionPath) { + cleanupConvertedImage(tempConversionPath) + } + }, + }, + } + } + + return { + ok: false, + error: "Error: Must provide either 'file_path' or 'image_data'.", + } +} diff --git a/src/tools/look-at/look-at-prompt.ts b/src/tools/look-at/look-at-prompt.ts new file mode 100644 index 000000000..585a8c38f --- /dev/null +++ b/src/tools/look-at/look-at-prompt.ts @@ -0,0 +1,18 @@ +export const READ_ENABLED = false + +export function buildLookAtPrompt(goal: string, isBase64Input: boolean): string { + const subjectNoun = isBase64Input ? "image" : "file" + const sourceClause = READ_ENABLED + ? "Use the Read tool on the provided file path to load its contents, then analyze it." + : `The ${subjectNoun} is already attached to this message. Analyze it directly from the attachment. Do NOT attempt to use the Read tool. The Read tool is disabled for this invocation and the ${subjectNoun} cannot be loaded by path.` + + return `Analyze the attached ${subjectNoun} and extract the requested information. + +${sourceClause} + +Goal: ${goal} + +Provide ONLY the extracted information that matches the goal. +Be thorough on what was requested, concise on everything else. +If the requested information is not found, clearly state what is missing.` +} diff --git a/src/tools/look-at/look-at-session-runner.ts b/src/tools/look-at/look-at-session-runner.ts new file mode 100644 index 000000000..5b87a7852 --- /dev/null +++ b/src/tools/look-at/look-at-session-runner.ts @@ -0,0 +1,107 @@ +import type { PluginInput } from "@opencode-ai/plugin" +import type { ToolContext } from "@opencode-ai/plugin/tool" +import { log, promptSyncWithModelSuggestionRetry } from "../../shared" +import { extractLatestAssistantText } from "./assistant-message-extractor" +import { MULTIMODAL_LOOKER_AGENT } from "./constants" +import { READ_ENABLED, buildLookAtPrompt } from "./look-at-prompt" +import type { LookAtFilePart } from "./look-at-input-preparer" +import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadata" + +interface RunLookAtSessionInput { + ctx: PluginInput + toolContext: ToolContext + goal: string + filePart: LookAtFilePart + isBase64Input: boolean +} + +export async function runLookAtSession({ + ctx, + toolContext, + goal, + filePart, + isBase64Input, +}: RunLookAtSessionInput): Promise { + const prompt = buildLookAtPrompt(goal, isBase64Input) + const { agentModel, agentVariant } = await resolveMultimodalLookerAgentMetadata(ctx) + + log(`[look_at] Creating session with parent: ${toolContext.sessionID}`) + const parentSession = await ctx.client.session.get({ + path: { id: toolContext.sessionID }, + }).catch(() => null) + const parentDirectory = parentSession?.data?.directory ?? ctx.directory + + const createResult = await ctx.client.session.create({ + body: { + parentID: toolContext.sessionID, + title: `look_at: ${goal.substring(0, 50)}`, + }, + query: { directory: parentDirectory }, + }) + + if (createResult.error) { + log("[look_at] Session create error:", createResult.error) + const errorString = String(createResult.error) + if (errorString.toLowerCase().includes("unauthorized")) { + return `Error: Failed to create session (Unauthorized). This may be due to: +1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only) +2. Provider authentication issues +3. Session permission inheritance problems + +Try using a different provider or API key authentication. + +Original error: ${createResult.error}` + } + + return `Error: Failed to create session: ${createResult.error}` + } + + const sessionID = createResult.data.id + log(`[look_at] Created session: ${sessionID}`) + + log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`) + try { + await promptSyncWithModelSuggestionRetry(ctx.client, { + path: { id: sessionID }, + body: { + agent: MULTIMODAL_LOOKER_AGENT, + tools: { + task: false, + call_omo_agent: false, + look_at: false, + read: READ_ENABLED, + }, + parts: [ + { type: "text", text: prompt }, + filePart, + ], + ...(agentModel ? { model: { providerID: agentModel.providerID, modelID: agentModel.modelID } } : {}), + ...(agentVariant ? { variant: agentVariant } : {}), + }, + }) + } catch (promptError) { + log("[look_at] Prompt error (ignored, will still fetch messages):", promptError) + } + + log(`[look_at] Fetching messages from session ${sessionID}...`) + const messagesResult = await ctx.client.session.messages({ + path: { id: sessionID }, + }) + + if (messagesResult.error) { + log("[look_at] Messages error:", messagesResult.error) + return `Error: Failed to get messages: ${messagesResult.error}` + } + + const messages = messagesResult.data + log(`[look_at] Got ${messages.length} messages`) + + const responseText = extractLatestAssistantText(messages) + if (!responseText) { + log("[look_at] No assistant message found") + return "Error: No response from multimodal-looker agent" + } + + log(`[look_at] Got response, length: ${responseText.length}`) + return responseText +} diff --git a/src/tools/look-at/tools.ts b/src/tools/look-at/tools.ts index 1296afd29..d6fbb3b01 100644 --- a/src/tools/look-at/tools.ts +++ b/src/tools/look-at/tools.ts @@ -1,43 +1,11 @@ -import { basename } from "node:path" -import { pathToFileURL } from "node:url" import { tool, type PluginInput, type ToolDefinition } from "@opencode-ai/plugin" -import { LOOK_AT_DESCRIPTION, MULTIMODAL_LOOKER_AGENT } from "./constants" +import { LOOK_AT_DESCRIPTION } from "./constants" import type { LookAtArgs } from "./types" -import { log, promptSyncWithModelSuggestionRetry } from "../../shared" -import { extractLatestAssistantText } from "./assistant-message-extractor" +import { log } from "../../shared" import type { LookAtArgsWithAlias } from "./look-at-arguments" import { normalizeArgs, validateArgs } from "./look-at-arguments" -import { - extractBase64Data, - inferMimeTypeFromBase64, - inferMimeTypeFromFilePath, -} from "./mime-type-inference" -import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadata" -import { - needsConversion, - convertImageToJpeg, - convertBase64ImageToJpeg, - cleanupConvertedImage, -} from "./image-converter" - -function getTemporaryConversionPath(error: unknown): string | null { - if (!(error instanceof Error)) { - return null - } - - const temporaryOutputPath = Reflect.get(error, "temporaryOutputPath") - if (typeof temporaryOutputPath === "string" && temporaryOutputPath.length > 0) { - return temporaryOutputPath - } - - const temporaryDirectory = Reflect.get(error, "temporaryDirectory") - if (typeof temporaryDirectory === "string" && temporaryDirectory.length > 0) { - return temporaryDirectory - } - - return null -} - +import { prepareLookAtInput } from "./look-at-input-preparer" +import { runLookAtSession } from "./look-at-session-runner" export { normalizeArgs, validateArgs } from "./look-at-arguments" @@ -57,188 +25,29 @@ export function createLookAt(ctx: PluginInput): ToolDefinition { return validationError } - const isBase64Input = Boolean(args.image_data) - const sourceDescription = isBase64Input ? "clipboard/pasted image" : args.file_path + const preparedInputResult = prepareLookAtInput(args) + if (!preparedInputResult.ok) { + return preparedInputResult.error + } + + const preparedInput = preparedInputResult.value + const { isBase64Input, sourceDescription } = preparedInput log(`[look_at] Analyzing ${sourceDescription}, goal: ${args.goal}`) - const imageData = args.image_data - const filePath = args.file_path - - let mimeType: string - let filePart: { type: "file"; mime: string; url: string; filename: string } - let tempFilePath: string | null = null - let tempConversionPath: string | null = null - let tempFilesToCleanup: string[] = [] - try { - if (imageData) { - mimeType = inferMimeTypeFromBase64(imageData) - - let finalBase64Data = extractBase64Data(imageData) - let finalMimeType = mimeType - - if (needsConversion(mimeType)) { - log(`[look_at] Detected unsupported Base64 format: ${mimeType}, converting to JPEG...`) - try { - const { base64, tempFiles } = convertBase64ImageToJpeg(finalBase64Data, mimeType) - finalBase64Data = base64 - finalMimeType = "image/jpeg" - tempFilesToCleanup = tempFiles - log(`[look_at] Base64 conversion successful`) - } catch (conversionError) { - log(`[look_at] Base64 conversion failed: ${conversionError}`) - return `Error: Failed to convert Base64 image format. ${conversionError}` - } - } - - filePart = { - type: "file", - mime: finalMimeType, - url: `data:${finalMimeType};base64,${finalBase64Data}`, - filename: `clipboard-image.${finalMimeType.split("/")[1] || "png"}`, - } - } else if (filePath) { - mimeType = inferMimeTypeFromFilePath(filePath) - - let actualFilePath = filePath - if (needsConversion(mimeType)) { - log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`) - try { - tempFilePath = convertImageToJpeg(filePath, mimeType) - tempConversionPath = tempFilePath - actualFilePath = tempFilePath - mimeType = "image/jpeg" - log(`[look_at] Conversion successful: ${tempFilePath}`) - } catch (conversionError) { - const failedConversionPath = getTemporaryConversionPath(conversionError) - if (failedConversionPath) { - tempConversionPath = failedConversionPath - } - log(`[look_at] Conversion failed: ${conversionError}`) - return `Error: Failed to convert image format. ${conversionError}` - } - } - - filePart = { - type: "file", - mime: mimeType, - url: pathToFileURL(actualFilePath).href, - filename: basename(actualFilePath), - } - } else { - return "Error: Must provide either 'file_path' or 'image_data'." - } - - const readEnabled = false - const subjectNoun = isBase64Input ? "image" : "file" - const sourceClause = readEnabled - ? `Use the Read tool on the provided file path to load its contents, then analyze it.` - : `The ${subjectNoun} is already attached to this message. Analyze it directly from the attachment. Do NOT attempt to use the Read tool. The Read tool is disabled for this invocation and the ${subjectNoun} cannot be loaded by path.` - - const prompt = `Analyze the attached ${subjectNoun} and extract the requested information. - -${sourceClause} - -Goal: ${args.goal} - -Provide ONLY the extracted information that matches the goal. -Be thorough on what was requested, concise on everything else. -If the requested information is not found, clearly state what is missing.` - - const { agentModel, agentVariant } = await resolveMultimodalLookerAgentMetadata(ctx) - - log(`[look_at] Creating session with parent: ${toolContext.sessionID}`) - const parentSession = await ctx.client.session.get({ - path: { id: toolContext.sessionID }, - }).catch(() => null) - const parentDirectory = parentSession?.data?.directory ?? ctx.directory - - const createResult = await ctx.client.session.create({ - body: { - parentID: toolContext.sessionID, - title: `look_at: ${args.goal.substring(0, 50)}`, - }, - query: { directory: parentDirectory }, - }) - - if (createResult.error) { - log(`[look_at] Session create error:`, createResult.error) - const errorStr = String(createResult.error) - if (errorStr.toLowerCase().includes("unauthorized")) { - return `Error: Failed to create session (Unauthorized). This may be due to: -1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only) -2. Provider authentication issues -3. Session permission inheritance problems - -Try using a different provider or API key authentication. - -Original error: ${createResult.error}` - } - return `Error: Failed to create session: ${createResult.error}` - } - - const sessionID = createResult.data.id - log(`[look_at] Created session: ${sessionID}`) - - log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`) - try { - await promptSyncWithModelSuggestionRetry(ctx.client, { - path: { id: sessionID }, - body: { - agent: MULTIMODAL_LOOKER_AGENT, - tools: { - task: false, - call_omo_agent: false, - look_at: false, - read: readEnabled, - }, - parts: [ - { type: "text", text: prompt }, - filePart, - ], - ...(agentModel ? { model: { providerID: agentModel.providerID, modelID: agentModel.modelID } } : {}), - ...(agentVariant ? { variant: agentVariant } : {}), - }, + return await runLookAtSession({ + ctx, + toolContext, + goal: args.goal, + filePart: preparedInput.filePart, + isBase64Input, }) - } catch (promptError) { - log(`[look_at] Prompt error (ignored, will still fetch messages):`, promptError) - } - - log(`[look_at] Fetching messages from session ${sessionID}...`) - - const messagesResult = await ctx.client.session.messages({ - path: { id: sessionID }, - }) - - if (messagesResult.error) { - log(`[look_at] Messages error:`, messagesResult.error) - return `Error: Failed to get messages: ${messagesResult.error}` - } - - const messages = messagesResult.data - log(`[look_at] Got ${messages.length} messages`) - - const responseText = extractLatestAssistantText(messages) - if (!responseText) { - log("[look_at] No assistant message found") - return "Error: No response from multimodal-looker agent" - } - - log(`[look_at] Got response, length: ${responseText.length}`) - return responseText } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) log(`[look_at] Unexpected error analyzing ${sourceDescription}:`, error) return `Error: Failed to analyze ${sourceDescription}: ${errorMessage}` } finally { - if (tempConversionPath) { - cleanupConvertedImage(tempConversionPath) - } else if (tempFilePath) { - cleanupConvertedImage(tempFilePath) - } - tempFilesToCleanup.forEach(file => { - cleanupConvertedImage(file) - }) + preparedInput.cleanup() } }, }) diff --git a/src/tools/skill-mcp/parse-skill-mcp-arguments.ts b/src/tools/skill-mcp/parse-skill-mcp-arguments.ts new file mode 100644 index 000000000..20e0b8158 --- /dev/null +++ b/src/tools/skill-mcp/parse-skill-mcp-arguments.ts @@ -0,0 +1,25 @@ +export function parseSkillMcpArguments( + argsJson: string | Record | undefined, +): Record { + if (!argsJson) return {} + if (typeof argsJson === "object" && argsJson !== null) { + return argsJson + } + + try { + const jsonString = argsJson.startsWith("'") && argsJson.endsWith("'") ? argsJson.slice(1, -1) : argsJson + const parsed = JSON.parse(jsonString) + if (typeof parsed !== "object" || parsed === null) { + throw new Error("Arguments must be a JSON object") + } + + return parsed as Record + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + throw new Error( + `Invalid arguments JSON: ${errorMessage}\n\n` + + `Expected a valid JSON object, e.g.: '{"key": "value"}'\n` + + `Received: ${argsJson}`, + ) + } +} diff --git a/src/tools/skill-mcp/tools.ts b/src/tools/skill-mcp/tools.ts index 2e1876575..25720baf8 100644 --- a/src/tools/skill-mcp/tools.ts +++ b/src/tools/skill-mcp/tools.ts @@ -1,6 +1,7 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { ToolContext } from "@opencode-ai/plugin/tool" import { BUILTIN_MCP_TOOL_HINTS, SKILL_MCP_DESCRIPTION } from "./constants" +import { parseSkillMcpArguments } from "./parse-skill-mcp-arguments" import type { SkillMcpArgs } from "./types" import type { SkillMcpManager, SkillMcpClientInfo, SkillMcpServerContext } from "../../features/skill-mcp-manager" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" @@ -82,30 +83,6 @@ function formatBuiltinMcpHint(mcpName: string): string | null { ) } -function parseArguments(argsJson: string | Record | undefined): Record { - if (!argsJson) return {} - if (typeof argsJson === "object" && argsJson !== null) { - return argsJson - } - try { - // Strip outer single quotes if present (common in LLM output) - const jsonStr = argsJson.startsWith("'") && argsJson.endsWith("'") ? argsJson.slice(1, -1) : argsJson - - const parsed = JSON.parse(jsonStr) - if (typeof parsed !== "object" || parsed === null) { - throw new Error("Arguments must be a JSON object") - } - return parsed as Record - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error) - throw new Error( - `Invalid arguments JSON: ${errorMessage}\n\n` + - `Expected a valid JSON object, e.g.: '{"key": "value"}'\n` + - `Received: ${argsJson}`, - ) - } -} - export function applyGrepFilter(output: string, pattern: string | undefined): string { if (!pattern) return output try { @@ -174,7 +151,7 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition skillName: found.skill.name, } - const parsedArgs = parseArguments(args.arguments) + const parsedArgs = parseSkillMcpArguments(args.arguments) let output: string switch (operation.type) { diff --git a/src/tools/skill/description-formatter.ts b/src/tools/skill/description-formatter.ts index fb8dd87c5..20907cda1 100644 --- a/src/tools/skill/description-formatter.ts +++ b/src/tools/skill/description-formatter.ts @@ -38,14 +38,17 @@ function formatSlashCommand(command: CommandInfo): string { return lines.join("\n") } -export function formatCombinedDescription(skills: SkillInfo[], commands: CommandInfo[]): string { - if (skills.length === 0 && commands.length === 0) { +export function formatCombinedDescription(skills?: SkillInfo[], commands?: CommandInfo[]): string { + const availableSkills = skills ?? [] + const availableCommands = commands ?? [] + + if (availableSkills.length === 0 && availableCommands.length === 0) { return TOOL_DESCRIPTION_NO_SKILLS } const availableItems = [ - ...sortByScopePriority(skills).map(formatSkillCommand), - ...sortByScopePriority(commands).map(formatSlashCommand), + ...sortByScopePriority(availableSkills).map(formatSkillCommand), + ...sortByScopePriority(availableCommands).map(formatSlashCommand), ] if (availableItems.length === 0) { diff --git a/src/tools/skill/session-skill-cache.ts b/src/tools/skill/session-skill-cache.ts new file mode 100644 index 000000000..040979ddb --- /dev/null +++ b/src/tools/skill/session-skill-cache.ts @@ -0,0 +1,10 @@ +const seenSessionIDs = new Set() + +export function shouldInvalidateSkillCacheForSession(sessionID?: string): boolean { + if (!sessionID || seenSessionIDs.has(sessionID)) { + return false + } + + seenSessionIDs.add(sessionID) + return true +} diff --git a/src/tools/skill/tools.factory.test.ts b/src/tools/skill/tools.factory.test.ts new file mode 100644 index 000000000..5b9a5ba30 --- /dev/null +++ b/src/tools/skill/tools.factory.test.ts @@ -0,0 +1,132 @@ +/// + +import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test" +import type { ToolContext } from "@opencode-ai/plugin/tool" +import type { LoadedSkill } from "../../features/opencode-skill-loader/types" +import * as skillContent from "../../features/opencode-skill-loader/skill-content" + +const discoverCommandsSync = mock(() => []) + +mock.module("../slashcommand/command-discovery", () => ({ + discoverCommandsSync, +})) + +function createMockSkill(name: string): LoadedSkill { + return { + name, + definition: { + name, + description: `Test skill ${name}`, + template: `Test skill template for ${name}`, + }, + scope: "config", + } +} + +async function flushMicrotasks(): Promise { + await Promise.resolve() + await Promise.resolve() +} + +const loadedSkill = createMockSkill("lazy-skill") +const getAllSkills = mock(async () => [loadedSkill]) +const clearSkillCache = mock(() => {}) +const mockContext: ToolContext = { + sessionID: "test-session", + messageID: "msg-1", + agent: "test-agent", + directory: "/test", + worktree: "/test", + abort: new AbortController().signal, + metadata: () => {}, + ask: async () => {}, +} + +function createMockContext(sessionID: string): ToolContext { + return { + ...mockContext, + sessionID, + } +} + +beforeEach(() => { + spyOn(skillContent, "getAllSkills").mockImplementation(getAllSkills) + spyOn(skillContent, "clearSkillCache").mockImplementation(clearSkillCache) +}) + +afterEach(async () => { + await flushMicrotasks() + mock.restore() +}) + +describe("createSkillTool", () => { + it("delays command discovery until the description getter is accessed", async () => { + // given + const baselineDiscoverCommandsSyncCalls = discoverCommandsSync.mock.calls.length + + // when + const { createSkillTool } = await import("./tools") + const skillTool = createSkillTool({}) + + // then + expect(discoverCommandsSync.mock.calls.length).toBe(baselineDiscoverCommandsSyncCalls) + + void skillTool.description + await flushMicrotasks() + + expect(discoverCommandsSync.mock.calls.length).toBe(baselineDiscoverCommandsSyncCalls + 1) + }) + + it("delays skill loading until execute is invoked", async () => { + // given + const baselineGetAllSkillsCalls = getAllSkills.mock.calls.length + + // when + const { createSkillTool } = await import("./tools") + const skillTool = createSkillTool({}) + + // then + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls) + + await skillTool.execute({ name: "lazy-skill" }, mockContext) + + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 1) + }) + + it("clears the shared skill cache once on first execute in a session", async () => { + // given + const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length + const sessionContext = createMockContext("session-clear-once") + + // when + const { createSkillTool } = await import("./tools") + const skillTool = createSkillTool({}) + void skillTool.description + await flushMicrotasks() + await skillTool.execute({ name: "lazy-skill" }, sessionContext) + await skillTool.execute({ name: "lazy-skill" }, sessionContext) + + // then + expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls + 1) + }) + + it("clears the skill discovery cache once per session", async () => { + // given + const baselineClearSkillCacheCalls = clearSkillCache.mock.calls.length + const baselineGetAllSkillsCalls = getAllSkills.mock.calls.length + const sessionAContext = createMockContext("session-a") + const sessionBContext = createMockContext("session-b") + const { createSkillTool } = await import("./tools") + const skillTool = createSkillTool({}) + + // when + await skillTool.execute({ name: "lazy-skill" }, sessionAContext) + await skillTool.execute({ name: "lazy-skill" }, sessionAContext) + await skillTool.execute({ name: "lazy-skill" }, sessionBContext) + await skillTool.execute({ name: "lazy-skill" }, sessionBContext) + + // then + expect(clearSkillCache.mock.calls.length).toBe(baselineClearSkillCacheCalls + 2) + expect(getAllSkills.mock.calls.length).toBe(baselineGetAllSkillsCalls + 4) + }) +}) diff --git a/src/tools/skill/tools.ts b/src/tools/skill/tools.ts index 0fada5607..d49936f95 100644 --- a/src/tools/skill/tools.ts +++ b/src/tools/skill/tools.ts @@ -2,9 +2,10 @@ import { dirname } from "node:path" import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { ToolContext } from "@opencode-ai/plugin/tool" import { TOOL_DESCRIPTION_PREFIX } from "./constants" +import { shouldInvalidateSkillCacheForSession } from "./session-skill-cache" import type { SkillArgs, SkillLoadOptions } from "./types" import type { LoadedSkill } from "../../features/opencode-skill-loader" -import { getAllSkills, clearSkillCache } from "../../features/opencode-skill-loader/skill-content" +import { clearSkillCache, getAllSkills } from "../../features/opencode-skill-loader/skill-content" import { injectGitMasterConfig } from "../../features/opencode-skill-loader/skill-content" import { discoverCommandsSync } from "../slashcommand/command-discovery" import type { CommandInfo } from "../slashcommand/types" @@ -27,12 +28,15 @@ import { export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition { let cachedDescription: string | null = null - const getSkills = async (): Promise => { - clearSkillCache() - const discovered = await getAllSkills({ + const getSkills = async (context?: ToolContext): Promise => { + if (shouldInvalidateSkillCacheForSession(context?.sessionID)) { + clearSkillCache() + } + + const discovered = (await getAllSkills({ disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider, - }) + })) ?? [] const allSkills = !options.skills ? discovered : [ @@ -57,7 +61,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition return discoverCommandsSync(undefined, { pluginsEnabled: options.pluginsEnabled, enabledPluginsOverride: options.enabledPluginsOverride, - }) + }) ?? [] } const buildDescription = async (force = false): Promise => { @@ -92,8 +96,6 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition } } else if (options.commands !== undefined) { cachedDescription = formatCombinedDescription([], options.commands) - } else { - void buildDescription() } return tool({ @@ -111,7 +113,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition .describe("Optional arguments or context for command invocation. Example: name='publish', user_message='patch'"), }, async execute(args: SkillArgs, ctx?: ToolContext) { - const skills = await getSkills() + const skills = await getSkills(ctx) const commands = getCommands() cachedDescription = formatCombinedDescription(skills.map(loadedSkillToInfo), commands) diff --git a/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts b/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts index 5dac1e7d9..32dd83bde 100644 --- a/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts +++ b/src/tools/skill/zauc-mocks-skill-tools/tools.test.ts @@ -1,7 +1,14 @@ +/// + +declare const require: NodeJS.Require + import { afterAll, beforeEach, describe, expect, it, mock, spyOn } from "bun:test" import type { ToolContext } from "@opencode-ai/plugin/tool" import * as fs from "node:fs" +import { tmpdir } from "node:os" +import { join } from "node:path" import { SkillMcpManager } from "../../../features/skill-mcp-manager" +import { clearSkillCache } from "../../../features/opencode-skill-loader/skill-content" import type { LoadedSkill } from "../../../features/opencode-skill-loader/types" import type { CommandInfo } from "../../slashcommand/types" import type { Tool as McpTool } from "@modelcontextprotocol/sdk/types.js" @@ -10,7 +17,24 @@ const originalReadFileSync = fs.readFileSync.bind(fs) let createSkillTool: typeof import("../tools").createSkillTool -beforeEach(async () => { +function clearRequireCache(modulePath: string): void { + const resolvedPath = require.resolve(modulePath) + if (require.cache?.[resolvedPath]) { + delete require.cache[resolvedPath] + } +} + +function requireFresh(modulePath: string): TModule { + clearRequireCache(modulePath) + return require(modulePath) as TModule +} + +beforeEach(() => { + mock.restore() + clearRequireCache("../tools") + clearRequireCache("../../../features/opencode-skill-loader/skill-content") + clearRequireCache("../../slashcommand/command-discovery") + mock.module("node:fs", () => ({ ...fs, readFileSync: (path: string, encoding?: string) => { @@ -23,9 +47,8 @@ Test skill body content` return originalReadFileSync(path, encoding as BufferEncoding) }, })) - - const module = await import("../tools") - createSkillTool = module.createSkillTool + + createSkillTool = requireFresh("../tools").createSkillTool }) afterAll(() => { @@ -548,16 +571,43 @@ describe("skill tool - ordering and priority", () => { }) describe("skill tool - dynamic discovery", () => { - it("discovers skills from disk on every invocation instead of caching", async () => { - // given: tool created with initial skills - const initialSkills = [createMockSkill("initial-skill")] - const tool = createSkillTool({ skills: initialSkills }) + it("caches discovered skills across tool instances until the shared cache resets", async () => { + // given + clearSkillCache() + const originalDirectory = process.cwd() + const temporaryDirectory = fs.mkdtempSync(join(tmpdir(), "skill-tool-cache-")) + const initialSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "initial-skill") + const secondSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "second-skill") - // when: executing with the initial skill name - const result = await tool.execute({ name: "initial-skill" }, mockContext) + fs.mkdirSync(initialSkillDirectory, { recursive: true }) + fs.writeFileSync(join(initialSkillDirectory, "SKILL.md"), "---\ndescription: Initial skill\n---\nInitial skill body") + process.chdir(temporaryDirectory) - // then: initial skill found (merged from options.skills since not on disk) - expect(result).toContain("Skill: initial-skill") + try { + const firstTool = createSkillTool({}) + + // when + const initialResult = await firstTool.execute({ name: "initial-skill" }, mockContext) + + fs.mkdirSync(secondSkillDirectory, { recursive: true }) + fs.writeFileSync(join(secondSkillDirectory, "SKILL.md"), "---\ndescription: Second skill\n---\nSecond skill body") + + const cachedTool = createSkillTool({}) + + // then + expect(initialResult).toContain("Skill: initial-skill") + let cachedError: Error | undefined + try { + await cachedTool.execute({ name: "second-skill" }, mockContext) + } catch (error) { + cachedError = error instanceof Error ? error : new Error(String(error)) + } + expect(cachedError?.message).toContain('Skill or command "second-skill" not found.') + } finally { + process.chdir(originalDirectory) + clearSkillCache() + fs.rmSync(temporaryDirectory, { recursive: true, force: true }) + } }) it("merges pre-provided skills with dynamically discovered ones", async () => { @@ -586,59 +636,66 @@ describe("skill tool - dynamic discovery", () => { }) }) describe("skill tool - dynamic description cache invalidation", () => { - it("rebuilds description after execute() discovers new skills", async () => { - // given: tool created with initial skills (no pre-provided skills) - // This triggers lazy description building + it("keeps description available after execute misses a skill", async () => { + // given const tool = createSkillTool({}) - - // Get initial description - it will build from empty or disk skills + + // when const initialDescription = tool.description expect(initialDescription).toBeString() - - // when: execute() is called, which clears cache AND gets fresh skills - // Note: In real scenario, execute() would discover new skills from disk - // For testing, we verify the mechanism: execute() should invalidate cachedDescription - - // Execute any skill to trigger the cache clear + getSkills flow - // Using a non-existent skill name to trigger the error path which still goes through getSkills() + try { await tool.execute({ name: "nonexistent-skill-12345" }, mockContext) - } catch (e) { - // Expected to fail - skill doesn't exist + } catch { } - - // then: cachedDescription should be invalidated, so next description access should rebuild - // We verify by checking that the description getter triggers a rebuild - // Since we can't easily mock getAllSkills in this test, we verify the cache invalidation mechanism - - // The key assertion: after execute(), the description should be rebuildable - // If cachedDescription wasn't invalidated, it would still return old value - // We verify by checking that the tool still has valid description structure + + // then expect(tool.description).toBeDefined() expect(typeof tool.description).toBe("string") }) - it("description reflects fresh skills after execute() clears cache", async () => { - // given: tool created without pre-provided skills (will use disk discovery) - const tool = createSkillTool({}) - - // when: execute() is called with a skill that exists on disk (via mock) - // This simulates the real scenario: execute() discovers skills, cache should be invalidated - - // Execute to trigger the cache invalidation path + it("picks up new disk skills only after the shared skill cache resets", async () => { + // given + clearSkillCache() + const originalDirectory = process.cwd() + const temporaryDirectory = fs.mkdtempSync(join(tmpdir(), "skill-tool-refresh-")) + const initialSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "initial-skill") + const secondSkillDirectory = join(temporaryDirectory, ".opencode", "skills", "second-skill") + + fs.mkdirSync(initialSkillDirectory, { recursive: true }) + fs.writeFileSync(join(initialSkillDirectory, "SKILL.md"), "---\ndescription: Initial skill\n---\nInitial skill body") + process.chdir(temporaryDirectory) + try { - // This will call getSkills() which clears cache - await tool.execute({ name: "nonexistent" }, mockContext) - } catch (e) { - // Expected + const initialTool = createSkillTool({}) + await initialTool.execute({ name: "initial-skill" }, mockContext) + + fs.mkdirSync(secondSkillDirectory, { recursive: true }) + fs.writeFileSync(join(secondSkillDirectory, "SKILL.md"), "---\ndescription: Second skill\n---\nSecond skill body") + + const cachedTool = createSkillTool({}) + let cachedError: Error | undefined + try { + await cachedTool.execute({ name: "second-skill" }, mockContext) + } catch (error) { + cachedError = error instanceof Error ? error : new Error(String(error)) + } + expect(cachedError?.message).toContain('Skill or command "second-skill" not found.') + + clearSkillCache() + const refreshedTool = createSkillTool({}) + + // when + const refreshedResult = await refreshedTool.execute({ name: "second-skill" }, mockContext) + + // then + expect(refreshedResult).toContain("Skill: second-skill") + expect(refreshedTool.description).toContain("second-skill") + } finally { + process.chdir(originalDirectory) + clearSkillCache() + fs.rmSync(temporaryDirectory, { recursive: true, force: true }) } - - // then: description should still work and not be stale - // The bug would cause it to return old cached value forever - const desc = tool.description - - // Verify description is a valid string (not stale/old) - expect(desc).toContain("skill") }) }) diff --git a/src/tools/slashcommand/command-discovery.test.ts b/src/tools/slashcommand/command-discovery.test.ts index e82cd7653..fc193b61f 100644 --- a/src/tools/slashcommand/command-discovery.test.ts +++ b/src/tools/slashcommand/command-discovery.test.ts @@ -326,4 +326,40 @@ describe("non-directory commands path", () => { expect(testCmd).toBeDefined() expect(testCmd?.content).toContain("Test command content.") }) + + it("#given excluded subdirectories under .claude/commands #when discoverCommandsSync runs #then prunes commands beneath them", () => { + // given + const projectDir = join(testDir, "project") + const commandsDir = join(projectDir, ".claude", "commands") + + mkdirSync(join(commandsDir, "node_modules", "fake-pkg"), { recursive: true }) + mkdirSync(join(commandsDir, ".git", "branches"), { recursive: true }) + mkdirSync(join(commandsDir, "dist"), { recursive: true }) + writeFileSync( + join(commandsDir, "real-cmd.md"), + "---\ndescription: Real command\n---\nRun real command.\n", + ) + writeFileSync( + join(commandsDir, "node_modules", "fake-pkg", "cmd.md"), + "---\ndescription: Nested command\n---\nRun nested command.\n", + ) + writeFileSync( + join(commandsDir, ".git", "branches", "cmd.md"), + "---\ndescription: Git command\n---\nRun git command.\n", + ) + writeFileSync( + join(commandsDir, "dist", "bundled-cmd.md"), + "---\ndescription: Bundled command\n---\nRun bundled command.\n", + ) + + // when + const commands = discoverCommandsSync(projectDir) + const names = commands.map((command) => command.name) + + // then + expect(names).toContain("real-cmd") + expect(names).not.toContain("node_modules/fake-pkg/cmd") + expect(names).not.toContain(".git/branches/cmd") + expect(names).not.toContain("dist/bundled-cmd") + }) }) diff --git a/src/tools/slashcommand/command-discovery.ts b/src/tools/slashcommand/command-discovery.ts index 7d220ab4f..855f6dc28 100644 --- a/src/tools/slashcommand/command-discovery.ts +++ b/src/tools/slashcommand/command-discovery.ts @@ -6,6 +6,7 @@ import { findProjectOpencodeCommandDirs, getOpenCodeCommandDirs, discoverPluginCommandDefinitions, + EXCLUDED_DIRS, } from "../../shared" import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types" import { isMarkdownFile } from "../../shared/file-utils" @@ -36,6 +37,7 @@ function discoverCommandsFromDir( for (const entry of entries) { if (entry.isDirectory()) { + if (EXCLUDED_DIRS.has(entry.name)) continue if (entry.name.startsWith(".")) continue const nestedPrefix = prefix ? `${prefix}${NESTED_COMMAND_SEPARATOR}${entry.name}` diff --git a/src/tools/slashcommand/execution-compatibility.test.ts b/src/tools/slashcommand/execution-compatibility.test.ts index 6d63bd678..a33b4bcc4 100644 --- a/src/tools/slashcommand/execution-compatibility.test.ts +++ b/src/tools/slashcommand/execution-compatibility.test.ts @@ -2,6 +2,7 @@ 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 { clearCommandLoaderCache } from "../../features/claude-code-command-loader" function requireFresh(modulePath: string): T { const resolvedPath = require.resolve(modulePath) @@ -25,12 +26,14 @@ describe("slashcommand discovery and execution compatibility", () => { let originalOpencodeConfigDir: string | undefined beforeEach(() => { + clearCommandLoaderCache() tempDir = mkdtempSync(join(tmpdir(), "omo-slashcommand-compat-test-")) originalWorkingDirectory = process.cwd() originalOpencodeConfigDir = process.env.OPENCODE_CONFIG_DIR }) afterEach(() => { + clearCommandLoaderCache() process.chdir(originalWorkingDirectory) if (originalOpencodeConfigDir === undefined) {