From 5b9e33cfef25ed76218dc6326460927363b391cf Mon Sep 17 00:00:00 2001 From: Imanol Maiztegui Date: Mon, 15 Jun 2026 14:48:05 +0200 Subject: [PATCH] refactor: kilo compat for v1.15.9 --- .github/workflows/close-prs.yml | 50 - .opencode-version | 2 +- .opencode/tool/github-triage.ts | 4 +- AGENTS.md | 8 + bun.lock | 360 +- nix/hashes.json | 8 +- package.json | 26 +- packages/containers/bun-node/Dockerfile | 2 +- packages/core/package.json | 12 +- packages/core/src/account.ts | 319 + packages/core/src/agent.ts | 147 + packages/core/src/auth.ts | 264 - packages/core/src/catalog.ts | 194 +- packages/core/src/event.ts | 4 +- packages/core/src/flag/flag.ts | 4 +- packages/core/src/location-layer.ts | 9 +- .../core/src/{models.ts => models-dev.ts} | 30 +- packages/core/src/models-snapshot.js | 71726 ---------------- packages/core/src/permission.ts | 45 + packages/core/src/plugin.ts | 81 +- packages/core/src/plugin/account.ts | 41 + packages/core/src/plugin/auth.ts | 27 - packages/core/src/plugin/boot.ts | 90 +- packages/core/src/plugin/env.ts | 16 +- packages/core/src/plugin/models-dev.ts | 102 +- .../src/plugin/provider/amazon-bedrock.ts | 21 +- .../core/src/plugin/provider/anthropic.ts | 14 +- packages/core/src/plugin/provider/azure.ts | 32 +- packages/core/src/plugin/provider/cerebras.ts | 12 +- .../plugin/provider/cloudflare-ai-gateway.ts | 2 +- .../plugin/provider/cloudflare-workers-ai.ts | 16 +- .../src/plugin/provider/github-copilot.ts | 16 +- .../core/src/plugin/provider/google-vertex.ts | 95 +- packages/core/src/plugin/provider/kilo.ts | 15 +- .../core/src/plugin/provider/llmgateway.ts | 19 +- packages/core/src/plugin/provider/nvidia.ts | 17 +- packages/core/src/plugin/provider/openai.ts | 16 +- packages/core/src/plugin/provider/opencode.ts | 25 +- .../core/src/plugin/provider/openrouter.ts | 29 +- packages/core/src/plugin/provider/vercel.ts | 14 +- packages/core/src/plugin/provider/zenmux.ts | 15 +- packages/core/src/provider.ts | 2 +- packages/core/src/util/error.ts | 1 + packages/core/src/util/wildcard.ts | 14 + packages/core/test/account.test.ts | 284 + packages/core/test/catalog.test.ts | 241 +- .../test/effect/cross-spawn-spawner.test.ts | 6 +- packages/core/test/models.test.ts | 8 +- .../plugin/provider-amazon-bedrock.test.ts | 39 +- .../test/plugin/provider-anthropic.test.ts | 34 +- .../provider-azure-cognitive-services.test.ts | 58 +- .../core/test/plugin/provider-azure.test.ts | 139 +- .../test/plugin/provider-cerebras.test.ts | 33 +- .../provider-cloudflare-workers-ai.test.ts | 109 +- .../plugin/provider-github-copilot.test.ts | 36 +- .../core/test/plugin/provider-gitlab.test.ts | 82 +- .../provider-google-vertex-anthropic.test.ts | 114 +- .../plugin/provider-google-vertex.test.ts | 146 +- packages/core/test/plugin/provider-helper.ts | 33 +- .../core/test/plugin/provider-kilo.test.ts | 90 +- .../test/plugin/provider-llmgateway.test.ts | 62 +- .../core/test/plugin/provider-nvidia.test.ts | 87 +- .../core/test/plugin/provider-openai.test.ts | 44 +- .../test/plugin/provider-opencode.test.ts | 224 +- .../test/plugin/provider-openrouter.test.ts | 93 +- .../core/test/plugin/provider-vercel.test.ts | 47 +- .../core/test/plugin/provider-zenmux.test.ts | 105 +- packages/effect-drizzle-sqlite/AGENTS.md | 19 + .../effect-drizzle-sqlite/examples/basic.ts | 92 + .../20240101000000_create_users/migration.sql | 4 + packages/effect-drizzle-sqlite/package.json | 29 + .../src/effect-sqlite/driver.ts | 77 + .../src/effect-sqlite/index.ts | 4 + .../src/effect-sqlite/migrator.ts | 14 + .../src/effect-sqlite/session.ts | 214 + packages/effect-drizzle-sqlite/src/index.ts | 6 + .../src/internal/drizzle-utils.ts | 127 + .../src/sqlite-core/effect/count.ts | 58 + .../src/sqlite-core/effect/db.ts | 296 + .../src/sqlite-core/effect/delete.ts | 261 + .../src/sqlite-core/effect/index.ts | 10 + .../src/sqlite-core/effect/insert.ts | 349 + .../src/sqlite-core/effect/query.ts | 198 + .../src/sqlite-core/effect/raw.ts | 49 + .../src/sqlite-core/effect/select.ts | 279 + .../src/sqlite-core/effect/session.ts | 490 + .../src/sqlite-core/effect/update.ts | 402 + .../src/up-migrations/effect-sqlite.ts | 102 + .../src/up-migrations/sqlite.ts | 253 + .../src/up-migrations/utils.ts | 45 + packages/effect-drizzle-sqlite/sst-env.d.ts | 10 + .../effect-drizzle-sqlite/test/sqlite.test.ts | 139 + packages/effect-drizzle-sqlite/tsconfig.json | 15 + packages/extensions/zed/extension.toml | 12 +- packages/http-recorder/package.json | 2 +- packages/llm/AGENTS.md | 80 +- packages/llm/README.md | 28 +- packages/llm/example/call-sites.md | 591 + packages/llm/example/tutorial.ts | 36 +- packages/llm/package.json | 2 +- packages/llm/src/cache-policy.ts | 2 +- packages/llm/src/index.ts | 3 +- packages/llm/src/llm.ts | 10 +- .../llm/src/protocols/anthropic-messages.ts | 118 +- .../llm/src/protocols/bedrock-converse.ts | 90 +- packages/llm/src/protocols/gemini.ts | 15 +- packages/llm/src/protocols/openai-chat.ts | 24 +- .../src/protocols/openai-compatible-chat.ts | 10 +- .../llm/src/protocols/openai-responses.ts | 260 +- packages/llm/src/protocols/shared.ts | 21 +- .../llm/src/protocols/utils/bedrock-auth.ts | 85 +- .../llm/src/protocols/utils/openai-options.ts | 5 + packages/llm/src/provider.ts | 20 +- packages/llm/src/providers/amazon-bedrock.ts | 51 +- packages/llm/src/providers/anthropic.ts | 37 +- packages/llm/src/providers/azure.ts | 115 +- packages/llm/src/providers/cloudflare.ts | 124 +- packages/llm/src/providers/github-copilot.ts | 68 +- packages/llm/src/providers/google.ts | 37 +- packages/llm/src/providers/index.ts | 1 + .../llm/src/providers/openai-compatible.ts | 80 +- packages/llm/src/providers/openai-options.ts | 3 +- packages/llm/src/providers/openai.ts | 60 +- packages/llm/src/providers/openrouter.ts | 44 +- packages/llm/src/providers/xai.ts | 62 +- packages/llm/src/route/auth.ts | 79 +- packages/llm/src/route/client.ts | 307 +- packages/llm/src/route/endpoint.ts | 28 +- packages/llm/src/route/index.ts | 7 +- packages/llm/src/route/transport/http.ts | 68 +- packages/llm/src/route/transport/index.ts | 13 +- packages/llm/src/route/transport/websocket.ts | 28 +- packages/llm/src/schema/events.ts | 6 +- packages/llm/src/schema/messages.ts | 54 +- packages/llm/src/schema/options.ts | 103 +- packages/llm/src/tool-runtime.ts | 20 +- packages/llm/src/utils/record.ts | 3 + packages/llm/test/adapter.test.ts | 99 +- packages/llm/test/auth-options.types.ts | 124 +- packages/llm/test/auth.test.ts | 4 +- packages/llm/test/cache-policy.test.ts | 36 +- packages/llm/test/continuation-scenarios.ts | 104 + packages/llm/test/endpoint.test.ts | 32 +- packages/llm/test/executor.test.ts | 10 +- packages/llm/test/exports.test.ts | 38 +- packages/llm/test/fixtures/media/restroom.png | Bin 0 -> 14496 bytes .../anthropic-opus-4-7-image-tool-result.json | 43 + .../gemini/gemini-2-5-flash-image.json | 32 + ...ached-tokens-on-identical-second-call.json | 4 +- ...i-responses-gpt-5-5-image-tool-result.json | 42 + ...ponses-gpt-5-5-reasoning-continuation.json | 58 + .../openai-responses-gpt-5-5-reasoning.json | 32 + packages/llm/test/generate-object.test.ts | 9 +- packages/llm/test/lib/http.ts | 10 +- packages/llm/test/lib/tool-runtime.ts | 1 - packages/llm/test/llm.test.ts | 51 +- packages/llm/test/provider.types.ts | 10 +- .../anthropic-messages-cache.recorded.test.ts | 7 +- .../anthropic-messages.recorded.test.ts | 7 +- .../test/provider/anthropic-messages.test.ts | 222 +- .../bedrock-converse-cache.recorded.test.ts | 7 +- .../test/provider/bedrock-converse.test.ts | 81 +- packages/llm/test/provider/cloudflare.test.ts | 44 +- .../provider/gemini-cache.recorded.test.ts | 7 +- packages/llm/test/provider/gemini.test.ts | 13 +- .../llm/test/provider/golden.recorded.test.ts | 87 +- .../llm/test/provider/openai-chat.test.ts | 53 +- .../provider/openai-compatible-chat.test.ts | 45 +- .../openai-responses-cache.recorded.test.ts | 7 +- .../test/provider/openai-responses.test.ts | 520 +- packages/llm/test/provider/openrouter.test.ts | 12 +- packages/llm/test/recorded-golden.ts | 22 +- packages/llm/test/recorded-scenarios.ts | 347 +- packages/llm/test/recorded-test.ts | 4 +- packages/llm/test/route.test.ts | 43 + packages/llm/test/schema.test.ts | 23 +- packages/llm/test/tool-runtime.test.ts | 57 +- packages/llm/test/tool.types.ts | 3 +- packages/opencode/.gitignore | 2 - packages/opencode/package.json | 20 +- packages/opencode/parsers-config.ts | 76 + packages/opencode/script/bench-test-suite.ts | 52 + packages/opencode/script/build-node.ts | 3 +- packages/opencode/script/build.ts | 5 +- packages/opencode/script/generate.ts | 13 +- .../opencode/script/profile-test-files.ts | 42 + packages/opencode/specs/tui-plugins.md | 63 + packages/opencode/src/account/account.ts | 3 + packages/opencode/src/account/repo.ts | 3 + packages/opencode/src/acp/agent.ts | 2 - packages/opencode/src/agent/agent.ts | 5 +- packages/opencode/src/bus/index.ts | 53 +- packages/opencode/src/cli/cmd/account.ts | 7 +- packages/opencode/src/cli/cmd/debug/agent.ts | 33 +- packages/opencode/src/cli/cmd/debug/v2.ts | 23 +- packages/opencode/src/cli/cmd/github.ts | 2 +- packages/opencode/src/cli/cmd/import.ts | 15 +- packages/opencode/src/cli/cmd/mcp.ts | 1 - packages/opencode/src/cli/cmd/models.ts | 2 +- packages/opencode/src/cli/cmd/providers.ts | 2 +- packages/opencode/src/cli/cmd/run.ts | 34 +- .../src/cli/cmd/run/footer.command.tsx | 141 +- .../src/cli/cmd/run/footer.prompt.tsx | 140 +- .../src/cli/cmd/run/footer.question.tsx | 4 +- .../src/cli/cmd/run/footer.subagent.tsx | 116 +- packages/opencode/src/cli/cmd/run/footer.ts | 28 +- .../opencode/src/cli/cmd/run/footer.view.tsx | 254 +- .../opencode/src/cli/cmd/run/prompt.shared.ts | 3 +- .../opencode/src/cli/cmd/run/runtime.queue.ts | 14 +- packages/opencode/src/cli/cmd/run/runtime.ts | 10 + .../opencode/src/cli/cmd/run/session-data.ts | 141 + .../src/cli/cmd/run/session-replay.ts | 188 + .../src/cli/cmd/run/session.shared.ts | 4 +- .../src/cli/cmd/run/stream.transport.ts | 409 +- .../opencode/src/cli/cmd/run/subagent-data.ts | 21 +- packages/opencode/src/cli/cmd/run/tool.ts | 35 +- packages/opencode/src/cli/cmd/run/types.ts | 8 + packages/opencode/src/cli/cmd/tui/app.tsx | 67 +- .../cli/cmd/tui/component/command-palette.tsx | 79 + .../src/cli/cmd/tui/component/dialog-tag.tsx | 3 + .../tui/component/dialog-workspace-create.tsx | 2 +- .../cmd/tui/component/prompt/autocomplete.tsx | 26 +- .../cli/cmd/tui/component/prompt/index.tsx | 32 +- .../src/cli/cmd/tui/component/prompt/part.ts | 7 + .../src/cli/cmd/tui/config/keybind.ts | 27 + .../cli/cmd/tui/context/command-palette.tsx | 163 - .../src/cli/cmd/tui/context/editor-zed.ts | 4 + .../src/cli/cmd/tui/context/editor.ts | 10 +- .../src/cli/cmd/tui/context/theme.tsx | 7 +- .../system/diff-viewer-file-tree-utils.ts | 232 + .../system/diff-viewer-file-tree.tsx | 162 + .../feature-plugins/system/diff-viewer-ui.tsx | 103 + .../feature-plugins/system/diff-viewer.tsx | 959 + .../tui/feature-plugins/system/session-v2.tsx | 70 +- packages/opencode/src/cli/cmd/tui/keymap.tsx | 125 +- .../opencode/src/cli/cmd/tui/plugin/api.tsx | 9 +- .../src/cli/cmd/tui/plugin/internal.ts | 2 + .../src/cli/cmd/tui/plugin/runtime.ts | 33 +- .../opencode/src/cli/cmd/tui/routes/home.tsx | 16 +- .../src/cli/cmd/tui/routes/session/index.tsx | 84 +- .../cli/cmd/tui/routes/session/permission.tsx | 11 +- .../cli/cmd/tui/routes/session/question.tsx | 21 +- .../tui/routes/session/subagent-footer.tsx | 11 +- .../src/cli/cmd/tui/ui/dialog-prompt.tsx | 41 +- .../opencode/src/cli/cmd/tui/ui/dialog.tsx | 11 +- .../cli/cmd/tui/util/collapse-tool-output.ts | 19 + .../src/cli/cmd/tui/util/selection.ts | 12 +- packages/opencode/src/config/agent.ts | 6 +- packages/opencode/src/config/command.ts | 4 +- packages/opencode/src/config/config.ts | 124 +- packages/opencode/src/config/entry-name.ts | 19 +- packages/opencode/src/config/managed.ts | 1 - packages/opencode/src/config/mcp.ts | 4 + packages/opencode/src/config/reference.ts | 46 + packages/opencode/src/config/variable.ts | 5 +- .../opencode/src/control-plane/workspace.ts | 7 +- packages/opencode/src/effect/app-runtime.ts | 2 +- .../opencode/src/effect/config-service.ts | 14 +- packages/opencode/src/effect/runtime-flags.ts | 1 + packages/opencode/src/env/index.ts | 3 + packages/opencode/src/event-v2-bridge.ts | 3 +- packages/opencode/src/file/index.ts | 3 + packages/opencode/src/file/ripgrep.ts | 3 + packages/opencode/src/format/index.ts | 3 + packages/opencode/src/installation/index.ts | 57 +- packages/opencode/src/mcp/auth.ts | 3 + packages/opencode/src/mcp/index.ts | 65 +- packages/opencode/src/mcp/oauth-provider.ts | 5 +- packages/opencode/src/permission/evaluate.ts | 16 +- packages/opencode/src/permission/index.ts | 64 +- packages/opencode/src/plugin/codex.ts | 67 +- packages/opencode/src/plugin/index.ts | 4 +- packages/opencode/src/plugin/loader.ts | 52 +- packages/opencode/src/plugin/xai.ts | 742 + .../opencode/src/project/instance-store.ts | 3 + packages/opencode/src/project/project.ts | 14 +- packages/opencode/src/project/vcs.ts | 61 +- packages/opencode/src/provider/auth.ts | 3 + .../opencode/src/provider/model-status.ts | 2 +- .../src/provider}/models-snapshot.d.ts | 0 .../opencode/src/provider/models-snapshot.js | 3 + packages/opencode/src/provider/provider.ts | 49 +- .../src/provider/sdk/copilot/AGENTS.md | 1 - packages/opencode/src/provider/transform.ts | 2 +- packages/opencode/src/pty/index.ts | 58 +- packages/opencode/src/question/index.ts | 60 +- packages/opencode/src/reference/reference.ts | 148 +- .../src/reference/repository-cache.ts | 209 +- .../server/routes/instance/httpapi/errors.ts | 175 + .../instance/httpapi/groups/instance.ts | 1 + .../routes/instance/httpapi/groups/mcp.ts | 11 +- .../instance/httpapi/groups/permission.ts | 3 +- .../routes/instance/httpapi/groups/project.ts | 3 +- .../instance/httpapi/groups/provider.ts | 2 +- .../routes/instance/httpapi/groups/pty.ts | 10 +- .../instance/httpapi/groups/question.ts | 5 +- .../routes/instance/httpapi/groups/session.ts | 12 +- .../instance/httpapi/groups/v2/message.ts | 9 +- .../instance/httpapi/groups/v2/model.ts | 6 +- .../instance/httpapi/groups/v2/provider.ts | 9 +- .../instance/httpapi/groups/v2/session.ts | 19 +- .../instance/httpapi/groups/workspace.ts | 3 +- .../routes/instance/httpapi/handlers/event.ts | 9 +- .../instance/httpapi/handlers/instance.ts | 6 +- .../routes/instance/httpapi/handlers/mcp.ts | 65 +- .../instance/httpapi/handlers/permission.ts | 22 +- .../instance/httpapi/handlers/project.ts | 13 +- .../instance/httpapi/handlers/provider.ts | 2 +- .../routes/instance/httpapi/handlers/pty.ts | 79 +- .../instance/httpapi/handlers/question.ts | 31 +- .../httpapi/handlers/session-errors.ts | 12 +- .../instance/httpapi/handlers/session.ts | 20 +- .../instance/httpapi/handlers/v2/message.ts | 45 +- .../instance/httpapi/handlers/v2/model.ts | 8 +- .../instance/httpapi/handlers/v2/provider.ts | 24 +- .../instance/httpapi/handlers/v2/session.ts | 134 +- .../instance/httpapi/handlers/workspace.ts | 2 + .../httpapi/middleware/authorization.ts | 60 +- .../instance/httpapi/middleware/error.ts | 11 +- .../httpapi/middleware/schema-error.ts | 14 +- .../httpapi/middleware/workspace-routing.ts | 35 +- .../server/routes/instance/httpapi/public.ts | 52 +- .../server/routes/instance/httpapi/server.ts | 6 +- packages/opencode/src/server/shared/fence.ts | 20 +- packages/opencode/src/session/llm.ts | 395 +- packages/opencode/src/session/llm/AGENTS.md | 90 + packages/opencode/src/session/llm/ai-sdk.ts | 254 + .../src/session/llm/native-request.ts | 196 + .../src/session/llm/native-runtime.ts | 143 + packages/opencode/src/session/llm/request.ts | 206 + packages/opencode/src/session/message-v2.ts | 1 + packages/opencode/src/session/processor.ts | 276 +- packages/opencode/src/session/prompt.ts | 439 +- .../opencode/src/session/prompt/plan-mode.txt | 70 + .../opencode/src/session/prompt/reference.ts | 73 + packages/opencode/src/session/reminders.ts | 91 + packages/opencode/src/session/session.ts | 21 +- packages/opencode/src/session/tools.ts | 208 + packages/opencode/src/share/session.ts | 2 +- packages/opencode/src/share/share-next.ts | 21 +- packages/opencode/src/skill/index.ts | 27 +- packages/opencode/src/sync/index.ts | 92 +- packages/opencode/src/tool/registry.ts | 17 +- packages/opencode/src/tool/repo_clone.ts | 23 +- packages/opencode/src/tool/skill.ts | 9 +- packages/opencode/src/tool/tool.ts | 31 +- packages/opencode/src/util/repository.ts | 116 +- packages/opencode/src/v2/session.ts | 75 +- packages/opencode/src/worktree/index.ts | 1 - packages/opencode/test/account/repo.test.ts | 40 +- .../opencode/test/account/service.test.ts | 22 +- .../agent/plan-mode-subagent-bypass.test.ts | 12 +- .../agent/plugin-agent-regression.test.ts | 4 +- packages/opencode/test/bus/bus-effect.test.ts | 98 +- packages/opencode/test/cli/account.test.ts | 6 +- .../opencode/test/cli/acp/acp-process.test.ts | 70 + .../__snapshots__/help-snapshots.test.ts.snap | 623 + .../test/cli/help/help-snapshots.test.ts | 132 + .../opencode/test/cli/run/entry.body.test.ts | 67 + .../test/cli/run/footer.view.test.tsx | 238 +- .../opencode/test/cli/run/run-process.test.ts | 84 + .../test/cli/run/runtime.queue.test.ts | 62 +- .../test/cli/run/scrollback.surface.test.ts | 83 + .../test/cli/run/session-data.test.ts | 184 + .../test/cli/run/session-replay.test.ts | 159 + .../test/cli/run/stream.transport.test.ts | 497 +- .../test/cli/run/subagent-data.test.ts | 2 +- .../test/cli/serve/serve-process.test.ts | 61 + .../test/cli/smokes/read-only.test.ts | 115 + .../test/cli/tui/dialog-prompt.test.tsx | 146 + .../tui/diff-viewer-file-tree-utils.test.ts | 323 + .../cli/tui/diff-viewer-file-tree.test.tsx | 197 + .../test/cli/tui/diff-viewer.test.tsx | 111 + .../test/cli/tui/editor-context-zed.test.ts | 32 +- .../opencode/test/cli/tui/keymap.test.tsx | 54 + .../test/cli/tui/plugin-lifecycle.test.ts | 4 +- .../test/cli/tui/plugin-loader.test.ts | 169 + .../test/cli/tui/plugin-toggle.test.ts | 64 + .../test/cli/tui/slot-replace.test.tsx | 9 +- .../opencode/test/config/agent-color.test.ts | 6 +- packages/opencode/test/config/config.test.ts | 2773 +- .../opencode/test/config/entry-name.test.ts | 57 + packages/opencode/test/config/tui.test.ts | 4 +- .../test/control-plane/workspace.test.ts | 1000 +- .../test/effect/runtime-flags.test.ts | 11 + packages/opencode/test/file/fsmonitor.test.ts | 4 +- .../opencode/test/file/path-traversal.test.ts | 4 +- packages/opencode/test/file/ripgrep.test.ts | 12 +- packages/opencode/test/file/watcher.test.ts | 64 +- packages/opencode/test/fixture/fixture.ts | 18 +- packages/opencode/test/fixture/plugin.ts | 10 + packages/opencode/test/fixture/tui-plugin.ts | 5 + .../session/native-anthropic-tool-loop.json | 49 + .../native-openai-oauth-tool-loop.json | 45 + .../session/native-zen-tool-loop.json | 49 + packages/opencode/test/format/format.test.ts | 6 +- .../test/installation/installation.test.ts | 74 +- packages/opencode/test/lib/cli-process.ts | 459 + packages/opencode/test/lib/effect.ts | 36 +- packages/opencode/test/lib/snapshot.ts | 73 + packages/opencode/test/lib/test-provider.ts | 37 + packages/opencode/test/mcp/lifecycle.test.ts | 20 +- .../test/mcp/oauth-auto-connect.test.ts | 6 +- .../opencode/test/mcp/oauth-provider.test.ts | 61 + .../opencode/test/permission-task.test.ts | 2 +- .../opencode/test/permission/next.test.ts | 8 +- .../test/plugin/auth-override.test.ts | 11 +- packages/opencode/test/plugin/codex.test.ts | 106 + .../test/plugin/install-concurrency.test.ts | 6 +- .../test/plugin/loader-shared.test.ts | 60 +- packages/opencode/test/plugin/trigger.test.ts | 19 +- .../test/plugin/workspace-adapter.test.ts | 17 +- packages/opencode/test/plugin/xai.test.ts | 634 + .../opencode/test/project/project.test.ts | 8 +- .../test/provider/amazon-bedrock.test.ts | 575 +- .../test/provider/model-status.test.ts | 2 +- .../opencode/test/provider/provider.test.ts | 3839 +- .../opencode/test/pty/pty-session.test.ts | 52 +- .../opencode/test/question/question.test.ts | 29 +- .../opencode/test/reference/reference.test.ts | 81 +- .../test/server/global-session-list.test.ts | 9 +- .../test/server/httpapi-authorization.test.ts | 38 +- .../server/httpapi-error-middleware.test.ts | 33 +- .../server/httpapi-event-diagnostics.test.ts | 279 + .../test/server/httpapi-event.test.ts | 166 +- .../test/server/httpapi-exercise/index.ts | 100 +- .../test/server/httpapi-experimental.test.ts | 2 +- .../server/httpapi-instance-context.test.ts | 2 +- .../test/server/httpapi-instance.test.ts | 79 + .../test/server/httpapi-listen.test.ts | 72 +- .../opencode/test/server/httpapi-mcp.test.ts | 32 + .../test/server/httpapi-provider.test.ts | 25 + .../opencode/test/server/httpapi-pty.test.ts | 82 + .../server/httpapi-public-openapi.test.ts | 219 + .../server/httpapi-schema-error-body.test.ts | 18 + .../opencode/test/server/httpapi-sdk.test.ts | 113 +- .../test/server/httpapi-session.test.ts | 263 +- .../opencode/test/server/httpapi-sync.test.ts | 2 +- .../server/httpapi-workspace-routing.test.ts | 2 +- .../test/server/httpapi-workspace.test.ts | 30 +- .../test/server/project-init-git.test.ts | 2 +- .../test/server/session-actions.test.ts | 5 +- .../server/session-diff-missing-patch.test.ts | 5 +- .../opencode/test/server/session-list.test.ts | 13 +- .../test/server/session-messages.test.ts | 5 +- .../test/server/session-select.test.ts | 2 +- .../opencode/test/session/compaction.test.ts | 356 +- .../test/session/llm-native-recorded.test.ts | 421 + .../opencode/test/session/llm-native.test.ts | 659 + packages/opencode/test/session/llm.test.ts | 1931 +- .../test/session/processor-effect.test.ts | 91 +- packages/opencode/test/session/prompt.test.ts | 653 +- .../opencode/test/session/session.test.ts | 2 +- .../test/session/snapshot-tool-race.test.ts | 2 + packages/opencode/test/session/system.test.ts | 5 + .../opencode/test/share/share-next.test.ts | 16 +- packages/opencode/test/skill/skill.test.ts | 31 + .../opencode/test/snapshot/snapshot.test.ts | 13 +- packages/opencode/test/sync/index.test.ts | 42 +- packages/opencode/test/tool/glob.test.ts | 114 +- packages/opencode/test/tool/grep.test.ts | 108 +- packages/opencode/test/tool/read.test.ts | 5 +- packages/opencode/test/tool/registry.test.ts | 98 +- .../opencode/test/tool/repo_clone.test.ts | 19 + packages/opencode/test/tool/skill.test.ts | 132 +- .../opencode/test/tool/tool-define.test.ts | 77 +- packages/opencode/test/tool/write.test.ts | 2 +- .../opencode/test/util/repository.test.ts | 93 + packages/plugin/package.json | 8 +- packages/plugin/src/tool.ts | 3 +- packages/plugin/src/tui.ts | 12 +- packages/script/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/sdk/js/script/build.ts | 18 + .../sdk/js/src/v2/gen/client/types.gen.ts | 2 +- packages/sdk/js/src/v2/gen/sdk.gen.ts | 203 +- packages/sdk/js/src/v2/gen/types.gen.ts | 1323 +- packages/sdk/openapi.json | 2627 +- packages/storybook/package.json | 2 +- packages/ui/package.json | 6 +- packages/ui/script/colors.txt | 55 + packages/ui/src/components/basic-tool.tsx | 77 +- packages/ui/src/components/logo.tsx | 2 +- packages/ui/src/components/markdown.tsx | 2 +- packages/ui/src/components/message-nav.css | 20 +- packages/ui/src/components/message-nav.tsx | 50 +- .../ui/src/components/message-part-text.ts | 3 + packages/ui/src/components/message-part.css | 2 +- .../ui/src/components/message-part.test.ts | 28 + packages/ui/src/components/message-part.tsx | 98 +- .../timeline-playground.stories.tsx | 2 +- packages/ui/src/context/data.tsx | 12 +- packages/ui/src/context/dialog.tsx | 3 +- packages/ui/src/i18n/ar.ts | 9 + packages/ui/src/i18n/br.ts | 9 + packages/ui/src/i18n/bs.ts | 9 + packages/ui/src/i18n/da.ts | 9 + packages/ui/src/i18n/de.ts | 9 + packages/ui/src/i18n/en.ts | 9 + packages/ui/src/i18n/es.ts | 9 + packages/ui/src/i18n/fr.ts | 9 + packages/ui/src/i18n/ja.ts | 9 + packages/ui/src/i18n/ko.ts | 9 + packages/ui/src/i18n/no.ts | 9 + packages/ui/src/i18n/pl.ts | 9 + packages/ui/src/i18n/ru.ts | 9 + packages/ui/src/i18n/th.ts | 9 + packages/ui/src/i18n/tr.ts | 9 + packages/ui/src/i18n/uk.ts | 167 + packages/ui/src/i18n/zh.ts | 8 + packages/ui/src/i18n/zht.ts | 8 + packages/ui/src/styles/tailwind/colors.css | 49 + packages/ui/src/theme/context.tsx | 4 + .../ui/src/v2/components/accordion-v2.css | 141 + .../v2/components/accordion-v2.stories.tsx | 177 + .../ui/src/v2/components/accordion-v2.tsx | 86 + packages/ui/src/v2/components/avatar-v2.css | 71 + .../src/v2/components/avatar-v2.stories.tsx | 85 + packages/ui/src/v2/components/avatar-v2.tsx | 59 + packages/ui/src/v2/components/badge-v2.css | 28 + .../ui/src/v2/components/badge-v2.stories.tsx | 54 + packages/ui/src/v2/components/badge-v2.tsx | 20 + .../ui/src/v2/components/basic-tool-v2.css | 164 + .../v2/components/basic-tool-v2.stories.tsx | 137 + .../ui/src/v2/components/basic-tool-v2.tsx | 139 + packages/ui/src/v2/components/button-v2.css | 147 + .../src/v2/components/button-v2.stories.tsx | 147 + packages/ui/src/v2/components/button-v2.tsx | 35 + packages/ui/src/v2/components/checkbox-v2.css | 181 + .../src/v2/components/checkbox-v2.stories.tsx | 92 + packages/ui/src/v2/components/checkbox-v2.tsx | 65 + packages/ui/src/v2/components/dialog-v2.css | 150 + .../src/v2/components/dialog-v2.stories.tsx | 174 + packages/ui/src/v2/components/dialog-v2.tsx | 77 + .../ui/src/v2/components/diff-changes-v2.css | 25 + .../v2/components/diff-changes-v2.stories.tsx | 60 + .../ui/src/v2/components/diff-changes-v2.tsx | 28 + packages/ui/src/v2/components/field-v2.css | 96 + .../ui/src/v2/components/field-v2.stories.tsx | 135 + packages/ui/src/v2/components/field-v2.tsx | 265 + .../ui/src/v2/components/icon-button-v2.css | 146 + .../v2/components/icon-button-v2.stories.tsx | 105 + .../ui/src/v2/components/icon-button-v2.tsx | 37 + packages/ui/src/v2/components/icon.tsx | 97 + .../ui/src/v2/components/inline-input-v2.css | 219 + .../v2/components/inline-input-v2.stories.tsx | 141 + .../ui/src/v2/components/inline-input-v2.tsx | 90 + packages/ui/src/v2/components/keybind-v2.css | 73 + .../src/v2/components/keybind-v2.stories.tsx | 82 + packages/ui/src/v2/components/keybind-v2.tsx | 30 + .../ui/src/v2/components/line-comment-v2.css | 205 + .../v2/components/line-comment-v2.stories.tsx | 88 + .../ui/src/v2/components/line-comment-v2.tsx | 155 + packages/ui/src/v2/components/menu-v2.css | 186 + .../ui/src/v2/components/menu-v2.stories.tsx | 216 + packages/ui/src/v2/components/menu-v2.tsx | 225 + packages/ui/src/v2/components/radio-v2.css | 202 + .../ui/src/v2/components/radio-v2.stories.tsx | 92 + packages/ui/src/v2/components/radio-v2.tsx | 72 + .../v2/components/segmented-control-v2.css | 81 + .../segmented-control-v2.stories.tsx | 107 + .../v2/components/segmented-control-v2.tsx | 208 + packages/ui/src/v2/components/select-v2.css | 196 + .../src/v2/components/select-v2.stories.tsx | 174 + packages/ui/src/v2/components/select-v2.tsx | 196 + packages/ui/src/v2/components/switch-v2.css | 150 + .../src/v2/components/switch-v2.stories.tsx | 64 + packages/ui/src/v2/components/switch-v2.tsx | 28 + packages/ui/src/v2/components/tabs-v2.css | 223 + .../ui/src/v2/components/tabs-v2.stories.tsx | 168 + packages/ui/src/v2/components/tabs-v2.tsx | 147 + .../ui/src/v2/components/text-input-v2.css | 145 + .../v2/components/text-input-v2.stories.tsx | 141 + .../ui/src/v2/components/text-input-v2.tsx | 67 + .../ui/src/v2/components/text-shimmer-v2.css | 125 + .../v2/components/text-shimmer-v2.stories.tsx | 70 + .../ui/src/v2/components/text-shimmer-v2.tsx | 63 + packages/ui/src/v2/components/textarea-v2.css | 78 + .../src/v2/components/textarea-v2.stories.tsx | 111 + packages/ui/src/v2/components/textarea-v2.tsx | 31 + packages/ui/src/v2/components/toast-v2.css | 201 + .../ui/src/v2/components/toast-v2.stories.tsx | 151 + packages/ui/src/v2/components/toast-v2.tsx | 144 + .../src/v2/components/tool-error-card-v2.css | 201 + .../components/tool-error-card-v2.stories.tsx | 91 + .../src/v2/components/tool-error-card-v2.tsx | 166 + packages/ui/src/v2/components/tooltip-v2.css | 54 + .../src/v2/components/tooltip-v2.stories.tsx | 91 + packages/ui/src/v2/components/tooltip-v2.tsx | 146 + packages/ui/src/v2/components/wordmark-v2.tsx | 92 + packages/ui/src/v2/styles/colors.css | 171 + packages/ui/src/v2/styles/tailwind.css | 2 + packages/ui/src/v2/styles/theme.css | 374 + patches/@ai-sdk%2Fxai@3.0.82.patch | 99 + perf/test-suite.md | 145 + screenshot-uk.png | Bin 0 -> 83462 bytes script/github/close-prs.ts | 393 - script/upgrade-opentui.ts | 137 +- specs/storage/effect-sqlite-package.md | 145 + specs/v2/instructions.md | 121 + specs/v2/provider-model.md | 56 +- 601 files changed, 46043 insertions(+), 85050 deletions(-) delete mode 100644 .github/workflows/close-prs.yml create mode 100644 packages/core/src/account.ts create mode 100644 packages/core/src/agent.ts delete mode 100644 packages/core/src/auth.ts rename packages/core/src/{models.ts => models-dev.ts} (91%) delete mode 100644 packages/core/src/models-snapshot.js create mode 100644 packages/core/src/permission.ts create mode 100644 packages/core/src/plugin/account.ts delete mode 100644 packages/core/src/plugin/auth.ts create mode 100644 packages/core/src/util/wildcard.ts create mode 100644 packages/core/test/account.test.ts create mode 100644 packages/effect-drizzle-sqlite/AGENTS.md create mode 100644 packages/effect-drizzle-sqlite/examples/basic.ts create mode 100644 packages/effect-drizzle-sqlite/examples/migrations/20240101000000_create_users/migration.sql create mode 100644 packages/effect-drizzle-sqlite/package.json create mode 100644 packages/effect-drizzle-sqlite/src/effect-sqlite/driver.ts create mode 100644 packages/effect-drizzle-sqlite/src/effect-sqlite/index.ts create mode 100644 packages/effect-drizzle-sqlite/src/effect-sqlite/migrator.ts create mode 100644 packages/effect-drizzle-sqlite/src/effect-sqlite/session.ts create mode 100644 packages/effect-drizzle-sqlite/src/index.ts create mode 100644 packages/effect-drizzle-sqlite/src/internal/drizzle-utils.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/count.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/db.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/delete.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/index.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/insert.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/query.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/raw.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/select.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/session.ts create mode 100644 packages/effect-drizzle-sqlite/src/sqlite-core/effect/update.ts create mode 100644 packages/effect-drizzle-sqlite/src/up-migrations/effect-sqlite.ts create mode 100644 packages/effect-drizzle-sqlite/src/up-migrations/sqlite.ts create mode 100644 packages/effect-drizzle-sqlite/src/up-migrations/utils.ts create mode 100644 packages/effect-drizzle-sqlite/sst-env.d.ts create mode 100644 packages/effect-drizzle-sqlite/test/sqlite.test.ts create mode 100644 packages/effect-drizzle-sqlite/tsconfig.json create mode 100644 packages/llm/example/call-sites.md create mode 100644 packages/llm/src/utils/record.ts create mode 100644 packages/llm/test/continuation-scenarios.ts create mode 100644 packages/llm/test/fixtures/media/restroom.png create mode 100644 packages/llm/test/fixtures/recordings/anthropic-messages/anthropic-opus-4-7-image-tool-result.json create mode 100644 packages/llm/test/fixtures/recordings/gemini/gemini-2-5-flash-image.json create mode 100644 packages/llm/test/fixtures/recordings/openai-responses/openai-responses-gpt-5-5-image-tool-result.json create mode 100644 packages/llm/test/fixtures/recordings/openai-responses/openai-responses-gpt-5-5-reasoning-continuation.json create mode 100644 packages/llm/test/fixtures/recordings/openai-responses/openai-responses-gpt-5-5-reasoning.json create mode 100644 packages/llm/test/route.test.ts create mode 100644 packages/opencode/script/bench-test-suite.ts create mode 100644 packages/opencode/script/profile-test-files.ts create mode 100644 packages/opencode/src/cli/cmd/run/session-replay.ts create mode 100644 packages/opencode/src/cli/cmd/tui/component/command-palette.tsx delete mode 100644 packages/opencode/src/cli/cmd/tui/context/command-palette.tsx create mode 100644 packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree-utils.ts create mode 100644 packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree.tsx create mode 100644 packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-ui.tsx create mode 100644 packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx create mode 100644 packages/opencode/src/cli/cmd/tui/util/collapse-tool-output.ts create mode 100644 packages/opencode/src/plugin/xai.ts rename packages/{core/src => opencode/src/provider}/models-snapshot.d.ts (100%) create mode 100644 packages/opencode/src/provider/models-snapshot.js delete mode 120000 packages/opencode/src/provider/sdk/copilot/AGENTS.md create mode 100644 packages/opencode/src/session/llm/AGENTS.md create mode 100644 packages/opencode/src/session/llm/ai-sdk.ts create mode 100644 packages/opencode/src/session/llm/native-request.ts create mode 100644 packages/opencode/src/session/llm/native-runtime.ts create mode 100644 packages/opencode/src/session/llm/request.ts create mode 100644 packages/opencode/src/session/prompt/plan-mode.txt create mode 100644 packages/opencode/src/session/prompt/reference.ts create mode 100644 packages/opencode/src/session/reminders.ts create mode 100644 packages/opencode/src/session/tools.ts create mode 100644 packages/opencode/test/cli/acp/acp-process.test.ts create mode 100644 packages/opencode/test/cli/help/__snapshots__/help-snapshots.test.ts.snap create mode 100644 packages/opencode/test/cli/help/help-snapshots.test.ts create mode 100644 packages/opencode/test/cli/run/run-process.test.ts create mode 100644 packages/opencode/test/cli/run/session-replay.test.ts create mode 100644 packages/opencode/test/cli/serve/serve-process.test.ts create mode 100644 packages/opencode/test/cli/smokes/read-only.test.ts create mode 100644 packages/opencode/test/cli/tui/dialog-prompt.test.tsx create mode 100644 packages/opencode/test/cli/tui/diff-viewer-file-tree-utils.test.ts create mode 100644 packages/opencode/test/cli/tui/diff-viewer-file-tree.test.tsx create mode 100644 packages/opencode/test/cli/tui/diff-viewer.test.tsx create mode 100644 packages/opencode/test/cli/tui/keymap.test.tsx create mode 100644 packages/opencode/test/config/entry-name.test.ts create mode 100644 packages/opencode/test/fixture/plugin.ts create mode 100644 packages/opencode/test/fixtures/recordings/session/native-anthropic-tool-loop.json create mode 100644 packages/opencode/test/fixtures/recordings/session/native-openai-oauth-tool-loop.json create mode 100644 packages/opencode/test/fixtures/recordings/session/native-zen-tool-loop.json create mode 100644 packages/opencode/test/lib/cli-process.ts create mode 100644 packages/opencode/test/lib/snapshot.ts create mode 100644 packages/opencode/test/lib/test-provider.ts create mode 100644 packages/opencode/test/mcp/oauth-provider.test.ts create mode 100644 packages/opencode/test/plugin/xai.test.ts create mode 100644 packages/opencode/test/server/httpapi-event-diagnostics.test.ts create mode 100644 packages/opencode/test/server/httpapi-public-openapi.test.ts create mode 100644 packages/opencode/test/session/llm-native-recorded.test.ts create mode 100644 packages/opencode/test/session/llm-native.test.ts create mode 100644 packages/opencode/test/util/repository.test.ts create mode 100644 packages/ui/src/components/message-part-text.ts create mode 100644 packages/ui/src/components/message-part.test.ts create mode 100644 packages/ui/src/i18n/uk.ts create mode 100644 packages/ui/src/v2/components/accordion-v2.css create mode 100644 packages/ui/src/v2/components/accordion-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/accordion-v2.tsx create mode 100644 packages/ui/src/v2/components/avatar-v2.css create mode 100644 packages/ui/src/v2/components/avatar-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/avatar-v2.tsx create mode 100644 packages/ui/src/v2/components/badge-v2.css create mode 100644 packages/ui/src/v2/components/badge-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/badge-v2.tsx create mode 100644 packages/ui/src/v2/components/basic-tool-v2.css create mode 100644 packages/ui/src/v2/components/basic-tool-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/basic-tool-v2.tsx create mode 100644 packages/ui/src/v2/components/button-v2.css create mode 100644 packages/ui/src/v2/components/button-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/button-v2.tsx create mode 100644 packages/ui/src/v2/components/checkbox-v2.css create mode 100644 packages/ui/src/v2/components/checkbox-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/checkbox-v2.tsx create mode 100644 packages/ui/src/v2/components/dialog-v2.css create mode 100644 packages/ui/src/v2/components/dialog-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/dialog-v2.tsx create mode 100644 packages/ui/src/v2/components/diff-changes-v2.css create mode 100644 packages/ui/src/v2/components/diff-changes-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/diff-changes-v2.tsx create mode 100644 packages/ui/src/v2/components/field-v2.css create mode 100644 packages/ui/src/v2/components/field-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/field-v2.tsx create mode 100644 packages/ui/src/v2/components/icon-button-v2.css create mode 100644 packages/ui/src/v2/components/icon-button-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/icon-button-v2.tsx create mode 100644 packages/ui/src/v2/components/icon.tsx create mode 100644 packages/ui/src/v2/components/inline-input-v2.css create mode 100644 packages/ui/src/v2/components/inline-input-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/inline-input-v2.tsx create mode 100644 packages/ui/src/v2/components/keybind-v2.css create mode 100644 packages/ui/src/v2/components/keybind-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/keybind-v2.tsx create mode 100644 packages/ui/src/v2/components/line-comment-v2.css create mode 100644 packages/ui/src/v2/components/line-comment-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/line-comment-v2.tsx create mode 100644 packages/ui/src/v2/components/menu-v2.css create mode 100644 packages/ui/src/v2/components/menu-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/menu-v2.tsx create mode 100644 packages/ui/src/v2/components/radio-v2.css create mode 100644 packages/ui/src/v2/components/radio-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/radio-v2.tsx create mode 100644 packages/ui/src/v2/components/segmented-control-v2.css create mode 100644 packages/ui/src/v2/components/segmented-control-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/segmented-control-v2.tsx create mode 100644 packages/ui/src/v2/components/select-v2.css create mode 100644 packages/ui/src/v2/components/select-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/select-v2.tsx create mode 100644 packages/ui/src/v2/components/switch-v2.css create mode 100644 packages/ui/src/v2/components/switch-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/switch-v2.tsx create mode 100644 packages/ui/src/v2/components/tabs-v2.css create mode 100644 packages/ui/src/v2/components/tabs-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/tabs-v2.tsx create mode 100644 packages/ui/src/v2/components/text-input-v2.css create mode 100644 packages/ui/src/v2/components/text-input-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/text-input-v2.tsx create mode 100644 packages/ui/src/v2/components/text-shimmer-v2.css create mode 100644 packages/ui/src/v2/components/text-shimmer-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/text-shimmer-v2.tsx create mode 100644 packages/ui/src/v2/components/textarea-v2.css create mode 100644 packages/ui/src/v2/components/textarea-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/textarea-v2.tsx create mode 100644 packages/ui/src/v2/components/toast-v2.css create mode 100644 packages/ui/src/v2/components/toast-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/toast-v2.tsx create mode 100644 packages/ui/src/v2/components/tool-error-card-v2.css create mode 100644 packages/ui/src/v2/components/tool-error-card-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/tool-error-card-v2.tsx create mode 100644 packages/ui/src/v2/components/tooltip-v2.css create mode 100644 packages/ui/src/v2/components/tooltip-v2.stories.tsx create mode 100644 packages/ui/src/v2/components/tooltip-v2.tsx create mode 100644 packages/ui/src/v2/components/wordmark-v2.tsx create mode 100644 packages/ui/src/v2/styles/colors.css create mode 100644 packages/ui/src/v2/styles/tailwind.css create mode 100644 packages/ui/src/v2/styles/theme.css create mode 100644 patches/@ai-sdk%2Fxai@3.0.82.patch create mode 100644 perf/test-suite.md create mode 100644 screenshot-uk.png delete mode 100755 script/github/close-prs.ts create mode 100644 specs/storage/effect-sqlite-package.md create mode 100644 specs/v2/instructions.md diff --git a/.github/workflows/close-prs.yml b/.github/workflows/close-prs.yml deleted file mode 100644 index a1e603a881..0000000000 --- a/.github/workflows/close-prs.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: close-prs - -on: - schedule: - - cron: "0 22 * * *" # Daily at 10:00 PM UTC - workflow_dispatch: - inputs: - dry-run: - description: "Log matching PRs without closing them" - type: boolean - default: true - max-close: - description: "Maximum matching PRs to close" - type: string - required: false - default: "50" - -jobs: - close: - runs-on: ubuntu-latest - timeout-minutes: 240 - permissions: - contents: read - issues: write - pull-requests: write - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - with: - bun-version: latest - - - name: Close old PRs without enough positive reactions - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - max_close="${{ inputs['max-close'] }}" - if [ -z "$max_close" ]; then - max_close="50" - fi - - args=("--threshold" "2" "--age-months" "1" "--sleep-ms" "20000" "--max-close" "$max_close") - - if [ "${{ github.event_name }}" = "schedule" ]; then - args+=("--execute") - elif [ "${{ inputs['dry-run'] }}" = "false" ]; then - args+=("--execute") - fi - - bun script/github/close-prs.ts "${args[@]}" diff --git a/.opencode-version b/.opencode-version index fff8b77730..7a00e5f13b 100644 --- a/.opencode-version +++ b/.opencode-version @@ -1 +1 @@ -v1.15.4 +v1.15.9 diff --git a/.opencode/tool/github-triage.ts b/.opencode/tool/github-triage.ts index 35db44641e..f25ca48b38 100644 --- a/.opencode/tool/github-triage.ts +++ b/.opencode/tool/github-triage.ts @@ -4,8 +4,8 @@ import { tool } from "@opencode-ai/plugin" const TEAM = { tui: ["kommander", "simonklee"], desktop_web: ["Hona", "Brendonovich"], - core: ["jlongster", "rekram1-node", "nexxeln", "kitlangton"], - inference: ["fwang", "MrMushrooooom"], + core: ["jlongster", "rekram1-node", "nexxeln", "kitlangton", "starptech"], + inference: ["fwang", "MrMushrooooom", "starptech"], windows: ["Hona"], } as const diff --git a/AGENTS.md b/AGENTS.md index 0b1998ec50..8e7ff342b5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,14 @@ - Local `main` ref may not exist; use `dev` or `origin/dev` for diffs. - Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility. +## Commits and PR Titles + +Use conventional commit-style messages and PR titles: `type(scope): summary`. + +Valid types are `feat`, `fix`, `docs`, `chore`, `refactor`, and `test`. Scopes are optional; use the affected package or area when helpful, e.g. `core`, `opencode`, `tui`, `app`, `desktop`, `sdk`, or `plugin`. + +Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`. + ## Style Guide ### General Principles diff --git a/bun.lock b/bun.lock index 344d1d4909..1e6aff8ee2 100644 --- a/bun.lock +++ b/bun.lock @@ -23,13 +23,13 @@ "oxlint-tsgolint": "0.21.0", "prettier": "3.6.2", "semver": "^7.6.0", - "sst": "3.18.10", + "sst": "4.13.1", "turbo": "2.8.13", }, }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/core": "workspace:*", @@ -44,6 +44,7 @@ "@solid-primitives/i18n": "2.2.1", "@solid-primitives/media": "2.3.3", "@solid-primitives/resize-observer": "2.1.5", + "@solid-primitives/scheduled": "1.5.3", "@solid-primitives/scroll": "2.1.3", "@solid-primitives/storage": "catalog:", "@solid-primitives/timer": "1.4.4", @@ -84,7 +85,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -119,7 +120,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -146,7 +147,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@ai-sdk/anthropic": "3.0.64", "@ai-sdk/openai": "3.0.48", @@ -168,7 +169,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -192,7 +193,7 @@ }, "packages/core": { "name": "@opencode-ai/core", - "version": "1.15.4", + "version": "1.15.9", "bin": { "opencode": "./bin/opencode", }, @@ -230,7 +231,7 @@ "ai-gateway-provider": "3.1.2", "cross-spawn": "catalog:", "effect": "catalog:", - "gitlab-ai-provider": "6.6.0", + "gitlab-ai-provider": "6.7.0", "glob": "13.0.5", "google-auth-library": "10.5.0", "immer": "11.1.4", @@ -253,8 +254,9 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { + "@zip.js/zip.js": "2.7.62", "drizzle-orm": "catalog:", "effect": "catalog:", "electron-context-menu": "4.1.2", @@ -305,9 +307,23 @@ "@parcel/watcher-win32-x64": "2.5.1", }, }, + "packages/effect-drizzle-sqlite": { + "name": "@opencode-ai/effect-drizzle-sqlite", + "version": "1.15.9", + "dependencies": { + "drizzle-orm": "catalog:", + "effect": "catalog:", + }, + "devDependencies": { + "@effect/sql-sqlite-bun": "catalog:", + "@tsconfig/bun": "catalog:", + "@types/bun": "catalog:", + "@typescript/native-preview": "catalog:", + }, + }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@opencode-ai/core": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -337,7 +353,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -353,7 +369,7 @@ }, "packages/http-recorder": { "name": "@opencode-ai/http-recorder", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@effect/platform-node": "catalog:", "effect": "catalog:", @@ -366,7 +382,7 @@ }, "packages/llm": { "name": "@opencode-ai/llm", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", @@ -384,7 +400,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.15.4", + "version": "1.15.9", "bin": { "opencode": "./bin/opencode", }, @@ -421,6 +437,7 @@ "@octokit/graphql": "9.0.2", "@octokit/rest": "catalog:", "@openauthjs/openauth": "catalog:", + "@opencode-ai/llm": "workspace:*", "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", @@ -453,7 +470,7 @@ "drizzle-orm": "catalog:", "effect": "catalog:", "fuzzysort": "3.1.0", - "gitlab-ai-provider": "6.6.0", + "gitlab-ai-provider": "6.7.0", "glob": "13.0.5", "google-auth-library": "10.5.0", "gray-matter": "4.0.3", @@ -489,6 +506,7 @@ "@babel/core": "7.28.4", "@octokit/webhooks-types": "7.6.1", "@opencode-ai/core": "workspace:*", + "@opencode-ai/http-recorder": "workspace:*", "@opencode-ai/script": "workspace:*", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", @@ -520,7 +538,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@opencode-ai/sdk": "workspace:*", "effect": "catalog:", @@ -536,9 +554,9 @@ "typescript": "catalog:", }, "peerDependencies": { - "@opentui/core": ">=0.2.11", - "@opentui/keymap": ">=0.2.11", - "@opentui/solid": ">=0.2.11", + "@opentui/core": ">=0.2.15", + "@opentui/keymap": ">=0.2.15", + "@opentui/solid": ">=0.2.15", }, "optionalPeers": [ "@opentui/core", @@ -558,7 +576,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "cross-spawn": "catalog:", }, @@ -573,7 +591,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -608,7 +626,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/core": "workspace:*", @@ -657,7 +675,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.15.4", + "version": "1.15.9", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -700,6 +718,7 @@ ], "patchedDependencies": { "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", + "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch", "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch", "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch", @@ -713,17 +732,18 @@ }, "catalog": { "@cloudflare/workers-types": "4.20251008.0", - "@effect/opentelemetry": "4.0.0-beta.65", - "@effect/platform-node": "4.0.0-beta.65", + "@effect/opentelemetry": "4.0.0-beta.66", + "@effect/platform-node": "4.0.0-beta.66", + "@effect/sql-sqlite-bun": "4.0.0-beta.66", "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@lydell/node-pty": "1.2.0-beta.10", "@npmcli/arborist": "9.4.0", "@octokit/rest": "22.0.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@opentui/core": "0.2.11", - "@opentui/keymap": "0.2.11", - "@opentui/solid": "0.2.11", + "@opentui/core": "0.2.15", + "@opentui/keymap": "0.2.15", + "@opentui/solid": "0.2.15", "@pierre/diffs": "1.1.0-beta.18", "@playwright/test": "1.59.1", "@sentry/solid": "10.36.0", @@ -735,7 +755,7 @@ "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", "@tsconfig/node22": "22.0.2", - "@types/bun": "1.3.12", + "@types/bun": "1.3.13", "@types/cross-spawn": "6.0.6", "@types/luxon": "3.7.1", "@types/node": "24.12.2", @@ -745,9 +765,9 @@ "cross-spawn": "7.0.6", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.19-d95b7a4", - "drizzle-orm": "1.0.0-beta.19-d95b7a4", - "effect": "4.0.0-beta.65", + "drizzle-kit": "1.0.0-rc.2", + "drizzle-orm": "1.0.0-rc.2", + "effect": "4.0.0-beta.66", "fuzzysort": "3.1.0", "hono": "4.10.7", "hono-openapi": "1.1.2", @@ -764,7 +784,7 @@ "tailwindcss": "4.1.11", "typescript": "5.8.2", "ulid": "3.0.1", - "virtua": "0.42.3", + "virtua": "0.49.1", "vite": "7.1.4", "vite-plugin-solid": "2.11.10", "zod": "4.1.8", @@ -888,6 +908,8 @@ "@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.993.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.11", "@aws-sdk/credential-provider-node": "^3.972.10", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.11", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.993.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.9", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.23.2", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.16", "@smithy/middleware-retry": "^4.4.33", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.10", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.5", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.32", "@smithy/util-defaults-mode-node": "^4.2.35", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7Ne3Yk/bgQPVebAkv7W+RfhiwTRSbfER9BtbhOa2w/+dIr902LrJf6vrZlxiqaJbGj2ALx8M+ZK1YIHVxSwu9A=="], + "@aws-sdk/client-lambda": ["@aws-sdk/client-lambda@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-ryEYNVdilyWkKsOs/7Xy/l7+qjtSz4sll8NpcWD6AtONxjG/5OMaAhxxDkQb4iBoNMKnISxsARzQAp/Wa8pXIg=="], + "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.933.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/credential-provider-node": "3.933.0", "@aws-sdk/middleware-bucket-endpoint": "3.930.0", "@aws-sdk/middleware-expect-continue": "3.930.0", "@aws-sdk/middleware-flexible-checksums": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-location-constraint": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-sdk-s3": "3.932.0", "@aws-sdk/middleware-ssec": "3.930.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/signature-v4-multi-region": "3.932.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-KxwZvdxdCeWK6o8mpnb+kk7Kgb8V+8AjTwSXUWH1UAD85B0tjdo1cSfE5zoR5fWGol4Ml5RLez12a6LPhsoTqA=="], "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zwGLSiK48z3PzKpQiDMKP85+fpIrPMF1qQOQW9OW7BGj5AuBZIisT2O4VzIgYJeh+t47MLU7VgBQL7muc+MJDg=="], @@ -958,6 +980,8 @@ "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@aws/durable-execution-sdk-js": ["@aws/durable-execution-sdk-js@1.0.2", "", { "dependencies": { "@aws-sdk/client-lambda": "^3.943.0" } }, "sha512-KIYBVqV9gArkWdPEDYOjJqLlO+NecmCXOXadNBlOspJTmqztwuiyb6aZc468bYWSGuL4Me/gyTIK97ubkwFNCw=="], + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], "@azure-rest/core-client": ["@azure-rest/core-client@2.6.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-iuFKDm8XPzNxPfRjhyU5/xKZmcRDzSuEghXDHHk4MjBV/wFL34GmYVBZnn9wmuoLBeS1qAw9ceMdaeJBPcB1QQ=="], @@ -1106,11 +1130,13 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], - "@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.65", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.65" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-0CD2fSsXrDM7FP2WFkbGJO1DwMqWR3UKHh6oBDXPHAPA+RsJSKoh3pLQsbQfldLuKnhOy87Bv0v9r9IdrIHCQw=="], + "@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-beta.66", "", { "peerDependencies": { "@opentelemetry/api": "^1.9", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": "^2.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": "^2.0.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "@opentelemetry/sdk-trace-web": "^2.0.0", "@opentelemetry/semantic-conventions": "^1.33.0", "effect": "^4.0.0-beta.66" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-LU3ejAzJS+4P+Qtfn9ULnsGcIPmx1tUUB2ZswFRL+EolD8US7zMljHTwGuQRUBJOjDwt7wFCMN5AR512vdY8FQ=="], - "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.65", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.65", "mime": "^4.1.0", "undici": "^8.0.2" }, "peerDependencies": { "effect": "^4.0.0-beta.65", "ioredis": "^5.7.0" } }, "sha512-QQy3KRcMwP0TngQdfQGl2u1zp03B7k7DuF5SNS8aZhD0dDBpKZpCwFad1ODY5qdY3ycPgMwBwKRRK7y/aw0C9w=="], + "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.66", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.66", "mime": "^4.1.0", "undici": "^8.0.2" }, "peerDependencies": { "effect": "^4.0.0-beta.66", "ioredis": "^5.7.0" } }, "sha512-s/0RgaQFuszzdorRnX1PwEQNnSOi+JgMJo3zEe9O2NR3sosMhTr0Uk+1AF6bUOI9uJ2CPT3KpTIIU7q5/TpOkg=="], - "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.65", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.65" } }, "sha512-3rY8F3WLEax6Hj08GI/OvDIH+KqjfxH7RM2bAMfgR75NgRmwDtny1P49PtPkoRjH5dcdtThThtsvE4X9OTZkpQ=="], + "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.66", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.66" } }, "sha512-+ymrhBnESv/hmn5SKTe2//IY9Ox/hGPeoogEWhW47ZGyhFI5eMYFxdEUBa+3IAV05rrBzrxON9lynu68n0DM7w=="], + + "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.66", "", { "peerDependencies": { "effect": "^4.0.0-beta.66" } }, "sha512-UYsrAb/5T0ZRypeN9Kmv3/ZInibGCjM6dtoiAWtfG+xKyuq8N05wmuVCXB0+XgVmUBxDWjw/S1fu4ivS0vZVuw=="], "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], @@ -1442,6 +1468,8 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ=="], + "@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], @@ -1540,6 +1568,8 @@ "@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"], + "@opencode-ai/effect-drizzle-sqlite": ["@opencode-ai/effect-drizzle-sqlite@workspace:packages/effect-drizzle-sqlite"], + "@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"], "@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"], @@ -1590,23 +1620,23 @@ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], - "@opentui/core": ["@opentui/core@0.2.11", "", { "dependencies": { "bun-ffi-structs": "0.2.2", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.2.11", "@opentui/core-darwin-x64": "0.2.11", "@opentui/core-linux-arm64": "0.2.11", "@opentui/core-linux-x64": "0.2.11", "@opentui/core-win32-arm64": "0.2.11", "@opentui/core-win32-x64": "0.2.11" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-X0zLmcDEvMrPzWYp769I7VEVb+og38vaete9tGZXu9HnJgu/paPUUplUT+6denBQccr2qx1rBYV6EtgbBpLEyw=="], + "@opentui/core": ["@opentui/core@0.2.15", "", { "dependencies": { "bun-ffi-structs": "0.2.2", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.2.15", "@opentui/core-darwin-x64": "0.2.15", "@opentui/core-linux-arm64": "0.2.15", "@opentui/core-linux-x64": "0.2.15", "@opentui/core-win32-arm64": "0.2.15", "@opentui/core-win32-x64": "0.2.15" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-YGHttdZWScMcSvtYgZkLR6VhUO1OoUiQzwYjZgIusf5eCkPLD8PapH+PTMVqAiX16CHO6JxfMlkHv5qDiHAccQ=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.2.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-h2MXtE2Cu3XlKVoQMXthnbhleO68zGXkoh/r1Q5pCoZh6RuXqns5/94D/aZThXBWwzPuEoyarMlxxR9OqrpvHw=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.2.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-s25f9GmZd6wxNM5ExRmwwnLT+NLCKxnTWuO9aObOlqsXfLMGHQZrb6YwgAn/PSTua98KmH7GJCVWdPgZ/P+0RQ=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.2.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-Y0jbPClnOBTPSIy+2THG86MTqIG/jGFlOOKuw4JfCDqEjPBM3pLWIHnJb3WxHRi2LlvfyBxvrUTXWlW6JpI0QQ=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.2.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-GyaipN+nOcEr8rcTO2mqKTGmOBk0C300I69fLtubD3BadHcMI1DVNlQrcf/J1mkQEuMYbmBTi/1hT1ybWGr2Mw=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.2.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-blQyyuTaW4q/OQ3whs7Kt7GCXhBUR5EQHHDdjOqQAr0HYpohUa6sbHMbiBcX2Ehc9ZWwtiaOoWiyZ5YXy2SAvg=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.2.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-h+uyufselGT4afKMP8Lg4yUl5Kp+DJBlhu3XpWXhphE5Pnq5+f0uGBr4P+34CNcWxMsDnvagSQLFRCS4rGrOWA=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.2.11", "", { "os": "linux", "cpu": "x64" }, "sha512-0nEB5+MgzQRYiVcQd1vHXPWNPWGh4JEmQTJKyG3OHnTzPaJ1FVSQ/V71ECyRSl3ymY3F+U0eW9cFgw1hCieK2w=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.2.15", "", { "os": "linux", "cpu": "x64" }, "sha512-jx+NImPq4wSp3Apfe7tlixiEJNnRyECTRJRWhGF6ZJz4PwFfgK2UHZKYR0DZHbV8nYawoDNQPJDXEWcoZShnMg=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.2.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-+KKH77fzm0qF8py9G2pU32DzB1bAgDMfBajrs7gKL5NtSEnknrwfh7hIs/tq41aF6j9zvIzgtykByh26tcjFog=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.2.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-2SQQLvf3sgmToxrNika9AdcccKrjPJEn5jW6sSv0oEixNBzUzW41vSZZG4LM/V3lL8eg0LoYDnRZeKLB4gwSqQ=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.2.11", "", { "os": "win32", "cpu": "x64" }, "sha512-dMmb9DX0W0HWadLdgciMbonqIc1xdcKiVmaQSYxw5eGCzFRPZIOrKHByesP+2ipkMuLx85W/MJUFal/lW8XSNg=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.2.15", "", { "os": "win32", "cpu": "x64" }, "sha512-SVMVgnC7LVEm+yVZKdmmhRBj/xAT94PanT+UCcHxaCWK+OLmv/AX+ohHq2m0odup6iXcEqj+7mAltO9fgJLFIg=="], - "@opentui/keymap": ["@opentui/keymap@0.2.11", "", { "dependencies": { "@opentui/core": "0.2.11" }, "peerDependencies": { "@opentui/react": "0.2.11", "@opentui/solid": "0.2.11", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-pCrJrY3mTuXdDaaRneId1JsJCtGE+7prTtWihzOLZzVJTJYyYtT38gMI7MpyAoloVDfEL5cTe8C+v7wv+IYREw=="], + "@opentui/keymap": ["@opentui/keymap@0.2.15", "", { "dependencies": { "@opentui/core": "0.2.15" }, "peerDependencies": { "@opentui/react": "0.2.15", "@opentui/solid": "0.2.15", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-wqQp6y7P2jZZJiOMwupxjGryuSWCs+njjglwW/xny9J17gomBmUvTIcIIWNG0Jv+EGO9ScBzCScGlwBHFhHyYw=="], - "@opentui/solid": ["@opentui/solid@0.2.11", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.2.11", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-M3WHxBFORHVE0yqMJYpi9PfjXWlnRTw/LYuBhZaJv0HTo+zTs60P/ukGcwnHDWnMpTGf3BH9x0Yi2dIqjHRY6Q=="], + "@opentui/solid": ["@opentui/solid@0.2.15", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.2.15", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-CViepAjsCWXwrLndMt+qlLo7cooVX7DXwSJHNizw7mfrRJtOPzSYJZCIk1vF4IJTWffCHygoYMe3uSeKvzAcbw=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], @@ -2148,7 +2178,7 @@ "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], - "@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="], + "@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.3", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-oNwLE6E6lxJAWrc8QXuwM0k2oU1BnANnkChwMw82aK1j3+mWGJkG1IFe5gCwbV+afYmjI76t9JJV3md/8tLw+g=="], "@solid-primitives/scroll": ["@solid-primitives/scroll@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-Ejq/Z7zKo/6eIEFr1bFLzXFxiGBCMLuqCM8QB8urr3YdPzjSETFLzYRWUyRiDWaBQN0F7k0SY6S7ig5nWOP7vg=="], @@ -2282,7 +2312,7 @@ "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], - "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="], + "@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="], "@types/cacache": ["@types/cacache@20.0.1", "", { "dependencies": { "@types/node": "*", "minipass": "*" } }, "sha512-QlKW3AFoFr/hvPHwFHMIVUH/ZCYeetBNou3PCmxu5LaNDvrtBlPJtIA6uhmU9JRt9oxj7IYoqoLcpxtzpPiTcw=="], @@ -2590,8 +2620,6 @@ "avvio": ["avvio@9.2.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ=="], - "aws-sdk": ["aws-sdk@2.1692.0", "", { "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", "xml2js": "0.6.2" } }, "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw=="], - "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], @@ -2676,7 +2704,7 @@ "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], - "buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="], + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], "buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="], @@ -2694,7 +2722,7 @@ "bun-pty": ["bun-pty@0.4.8", "", {}, "sha512-rO70Mrbr13+jxHHHu2YBkk2pNqrJE5cJn29WE++PUr+GFA0hq/VgtQPZANJ8dJo6d7XImvBk37Innt8GM7O28w=="], - "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], + "bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], @@ -2972,9 +3000,9 @@ "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], - "drizzle-kit": ["drizzle-kit@1.0.0-beta.19-d95b7a4", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "get-tsconfig": "^4.13.6", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-M0sqc+42TYBod6kEZ3AsW6+JWe3+76gR1aDFbHH5DmuLKEwewmbzlhBG6qnvV6YA1cIIbkuam3dC7r6PREOCXw=="], + "drizzle-kit": ["drizzle-kit@1.0.0-rc.2", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "get-tsconfig": "^4.13.6", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-TRxUmj1wDA2QCt3GvuhfamvIa66wJ7+MzSxBMKkpRtYScjHTumT9BE+x6daSzuEacSrPEuUH5/cW1uo5RkoPIg=="], - "drizzle-orm": ["drizzle-orm@1.0.0-beta.19-d95b7a4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-bZZKKeoRKrMVU6zKTscjrSH0+WNb1WEi3N0Jl4wEyQ7aQpTgHzdYY6IJQ1P0M74HuSJVeX4UpkFB/S6dtqLEJg=="], + "drizzle-orm": ["drizzle-orm@1.0.0-rc.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql-pg": ">=4.0.0-beta.58 || >=4.0.0", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "effect": ">=4.0.0-beta.58 || >=4.0.0", "expo-sqlite": ">=14.0.0", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/mssql", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "effect", "expo-sqlite", "mssql", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-UXYDkbplF5wX0hwxll+80QhEwUvAJLBu+tAK/d4fna18kLE6VuliAzufF/ieDEIJeSnLRYgtmsXD6x1Xuy1kIg=="], "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], @@ -2988,7 +3016,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "effect": ["effect@4.0.0-beta.65", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-QYKvQPAj3CmtsvWkHQww15wX4KG2gNsszDWEcOO5sZCMknp66u6Si/Opmt3wwWCwsyvRmDAdIg+JIz5qzbbFIw=="], + "effect": ["effect@4.0.0-beta.66", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-4arEr62cziFa8BBVDUwJCJJmaVepXf/kRg7KtC0h8+bufngscrHbwWFhr9c+HonwOF+31U3iD3xUJmw9KzX7Dw=="], "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], @@ -3272,7 +3300,7 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], - "gitlab-ai-provider": ["gitlab-ai-provider@6.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-jUxYnKA4XQaPc3wxACDZ8bPDXO0Mzx7cZaBDxbT2uGgLqtGZmSi+9tVNIg7louSS+s/ioVra3SoUz3iOFVhKPA=="], + "gitlab-ai-provider": ["gitlab-ai-provider@6.7.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-J7apROAmDwDJcLPcbQ9YQiPhyFN1Vvt/f3ugsePaUnzh3sedfHCHGETgG0Mm0dJCB2rC7DYwmV/sgxLQcQ/sjw=="], "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], @@ -3414,7 +3442,7 @@ "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], - "ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], @@ -3546,7 +3574,7 @@ "is64bit": ["is64bit@2.0.0", "", { "dependencies": { "system-architecture": "^0.1.0" } }, "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw=="], - "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="], @@ -3564,8 +3592,6 @@ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "jmespath": ["jmespath@0.16.0", "", {}, "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw=="], - "jose": ["jose@6.0.11", "", {}, "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg=="], "js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], @@ -4052,8 +4078,6 @@ "opencode-poe-auth": ["opencode-poe-auth@0.0.1", "", { "dependencies": { "open": "^10.0.0", "poe-oauth": "*" }, "peerDependencies": { "@opencode-ai/plugin": "*" } }, "sha512-cXqTlS6AXHzo1oBdosnxbT47ZJEZ9WXn050X8Re6wZ1vaNnTpB/l2fMQt90evT7RBK0fB8UjXQUDMKyd7bbiqg=="], - "opencontrol": ["opencontrol@0.0.6", "", { "dependencies": { "@modelcontextprotocol/sdk": "1.6.1", "@tsconfig/bun": "1.0.7", "hono": "4.7.4", "zod": "3.24.2", "zod-to-json-schema": "3.24.3" }, "bin": { "opencontrol": "bin/index.mjs" } }, "sha512-QeCrpOK5D15QV8kjnGVeD/BHFLwcVr+sn4T6KKmP0WAMs2pww56e4h+eOGHb5iPOufUQXbdbBKi6WV2kk7tefQ=="], - "openid-client": ["openid-client@5.6.4", "", { "dependencies": { "jose": "^4.15.4", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" } }, "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA=="], "opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="], @@ -4250,7 +4274,7 @@ "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], - "punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "pupa": ["pupa@3.3.0", "", { "dependencies": { "escape-goat": "^4.0.0" } }, "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA=="], @@ -4260,8 +4284,6 @@ "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], - "querystring": ["querystring@0.2.0", "", {}, "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], @@ -4446,7 +4468,7 @@ "sanitize-filename": ["sanitize-filename@1.6.4", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg=="], - "sax": ["sax@1.2.1", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="], + "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], @@ -4574,23 +4596,23 @@ "ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], - "sst": ["sst@3.18.10", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.18.10", "sst-darwin-x64": "3.18.10", "sst-linux-arm64": "3.18.10", "sst-linux-x64": "3.18.10", "sst-linux-x86": "3.18.10", "sst-win32-arm64": "3.18.10", "sst-win32-x64": "3.18.10", "sst-win32-x86": "3.18.10" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-SY+ldeJ9K5E9q+DhjXA3e2W3BEOzBwkE3IyLSD71uA3/5nRhUAST31iOWEpW36LbIvSQ9uOVDFcebztoLJ8s7w=="], + "sst": ["sst@4.13.1", "", { "dependencies": { "@aws/durable-execution-sdk-js": "1.0.2", "aws4fetch": "1.0.18", "jose": "5.2.3", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "4.13.1", "sst-darwin-x64": "4.13.1", "sst-linux-arm64": "4.13.1", "sst-linux-x64": "4.13.1", "sst-linux-x86": "4.13.1", "sst-win32-arm64": "4.13.1", "sst-win32-x64": "4.13.1", "sst-win32-x86": "4.13.1" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-FKzhWuqV5NPhFWH7b+Ktf5+Mvox6DCMc8iOrjaS3mkjnnmyEcOZq7HNx2/ZlIcBwgOZE9sCPR3ot1zXtXkXzZg=="], - "sst-darwin-arm64": ["sst-darwin-arm64@3.18.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3MwIpMZhhdZKDqLp9ZQNlwkWix5+q+N0PWstuTomYwgZOxCCe6u9IIsoIszSk+GAJJN/jvGZyLiXKeV4iiQvw=="], + "sst-darwin-arm64": ["sst-darwin-arm64@4.13.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gGwfgZGOsulU6iGeZJtxP5BpSZFsRUy1dG/yTqJa++n1P1APWXZC64u2qRHm6rdwLAjEeWaCQ9k7ouKgn0zh5Q=="], - "sst-darwin-x64": ["sst-darwin-x64@3.18.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-nQ0jMKkPOa+kj6Ygz8+kYhBua/vgNTLkd+4r8NSmk7v+Zs78lKnx3T//kEzS0yik6Q6QwGfokwrTcA1Jii2xSw=="], + "sst-darwin-x64": ["sst-darwin-x64@4.13.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-RcKLI2oAY+Wk5fWUF0gJFKvwMSpid3qw9L3OcfgFL2ymZH652ybLpQPBxtoJ95FdyknWIMnYf6ZK9C2jnH5eaw=="], - "sst-linux-arm64": ["sst-linux-arm64@3.18.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-mj9VNj3SvLS+HaXx2PhCX0aTA7CwJNoM6JhRc0s/zCilqchcvqDjbhpYBJO4brEPv6aOaaa7T3WvIQqtYauK4Q=="], + "sst-linux-arm64": ["sst-linux-arm64@4.13.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Lp/8BWhH8KZnb50xPd8A6bkZ7QqCH3Dar9l16TPwuAmPxxRUlkmg42h+ACZ9n02vSJl8y/WLnV4JB6SgJpRFVg=="], - "sst-linux-x64": ["sst-linux-x64@3.18.10", "", { "os": "linux", "cpu": "x64" }, "sha512-7iy1Eq2eqnT9Ag/8OVgC04vRjV7AAQyf/BvzLc+6Sz+GvRiKA8VEuPnbXNYQF+NIvEqsawfcd7MknSTtImpsvQ=="], + "sst-linux-x64": ["sst-linux-x64@4.13.1", "", { "os": "linux", "cpu": "x64" }, "sha512-f4eHOsApoP+CpUzLUGzfoTBYsqqr6nl/M0gjYsVNi1T+6v92lc84AhQ4DoDZx033QggyxkqRezj8jOkjkKxa7w=="], - "sst-linux-x86": ["sst-linux-x86@3.18.10", "", { "os": "linux", "cpu": "none" }, "sha512-77qZSuPZeQ5bdRCiq1pQEdY8EcGNHboKrx4P2yFid2FBDKJsXxOXtIxJdloyx+ljBn0+nxl/g040QBmXxdc9tA=="], + "sst-linux-x86": ["sst-linux-x86@4.13.1", "", { "os": "linux", "cpu": "none" }, "sha512-5OHdtPa0GmozDpBPdsD9Tv+SGnpjJSoTXptgK59ivQg3UYNWBBotidvEyUJs1MU9B/3+I+Fmw32zsF2O+ZtPgg=="], - "sst-win32-arm64": ["sst-win32-arm64@3.18.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-aY+FhMxvYs8crlrKALpLn/kKmud8YQj6LkMHsrOAAIJhfNyxhCja2vrYQaY+bcqdsS5W2LMVcS2hyaMqKXZKcg=="], + "sst-win32-arm64": ["sst-win32-arm64@4.13.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-qAUuCQj6wDdZ84a9W4FhnRTHYlEnYRHGYFqO3cmMImbnAQEoKSQR1XuWqt0Ev4RT3kU4Lz/fgvJjGkR7WUstLg=="], - "sst-win32-x64": ["sst-win32-x64@3.18.10", "", { "os": "win32", "cpu": "x64" }, "sha512-rY+yJXOpG+P5xXnaQRpCvBK2zwwLhjzpYidGkp6F+cGgiVdh2Wre/CIQNRaVHr20ncj8lLe/RsHWa9QCNM48jg=="], + "sst-win32-x64": ["sst-win32-x64@4.13.1", "", { "os": "win32", "cpu": "x64" }, "sha512-r+83NMwpe4MLAvkVoOxi1KNs6nIqilFucsTr+VN1PgknsiVBY1emITjSWS2jDJJMuH8xJXL5xJzF/l5rcKWErg=="], - "sst-win32-x86": ["sst-win32-x86@3.18.10", "", { "os": "win32", "cpu": "none" }, "sha512-pq8SmV0pIjBFMY6DraUZ4akyTxHnfjIKCRbBLdMxFUZK8TzA1NK2YdjRt1AwrgXRYGRyctrz/mt4WyO0SMOVQQ=="], + "sst-win32-x86": ["sst-win32-x86@4.13.1", "", { "os": "win32", "cpu": "none" }, "sha512-YPxBVdac/MsrzwlC6pF0NrrvMcmfdBLYjv7MbzHc5jNh1FQ1WPh6bdWQqgv0KD9EQTNLLEkej0beydgUvcCWJg=="], "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], @@ -4870,8 +4892,6 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="], - "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], @@ -4880,8 +4900,6 @@ "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], - "util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], @@ -4904,7 +4922,7 @@ "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "virtua": ["virtua@0.42.3", "", { "peerDependencies": { "react": ">=16.14.0", "react-dom": ">=16.14.0", "solid-js": ">=1.0", "svelte": ">=5.0", "vue": ">=3.2" }, "optionalPeers": ["react", "react-dom", "solid-js", "svelte", "vue"] }, "sha512-5FoAKcEvh05qsUF97Yz42SWJ7bwnPExjUYHGuoxz1EUtfWtaOgXaRwnylJbDpA0QcH1rKvJ2qsGRi9MK1fpQbg=="], + "virtua": ["virtua@0.49.1", "", { "peerDependencies": { "react": ">=16.14.0", "react-dom": ">=16.14.0", "solid-js": ">=1.0", "svelte": ">=5.0", "vue": ">=3.2" }, "optionalPeers": ["react", "react-dom", "solid-js", "svelte", "vue"] }, "sha512-6f79msqg3jzNFdqJiS0FSzhRN1EHlDhR7EvW7emp6z5qQ22VdsReiDHflkpMEMhoAyUuYr69nwT0aagiM7NrUg=="], "vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="], @@ -5008,6 +5026,8 @@ "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], + "xml-naming": ["xml-naming@0.1.0", "", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="], + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], @@ -5170,6 +5190,20 @@ "@aws-sdk/client-cognito-identity/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], + "@aws-sdk/client-lambda/@aws-sdk/core": ["@aws-sdk/core@3.974.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.24", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.42", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.37", "@aws-sdk/credential-provider-http": "^3.972.39", "@aws-sdk/credential-provider-ini": "^3.972.41", "@aws-sdk/credential-provider-process": "^3.972.37", "@aws-sdk/credential-provider-sso": "^3.972.41", "@aws-sdk/credential-provider-web-identity": "^3.972.41", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ=="], + + "@aws-sdk/client-lambda/@aws-sdk/types": ["@aws-sdk/types@3.973.8", "", { "dependencies": { "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw=="], + + "@aws-sdk/client-lambda/@smithy/core": ["@smithy/core@3.24.3", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg=="], + + "@aws-sdk/client-lambda/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A=="], + + "@aws-sdk/client-lambda/@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="], + + "@aws-sdk/client-lambda/@smithy/types": ["@smithy/types@4.14.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg=="], + "@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], "@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="], @@ -5634,28 +5668,18 @@ "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "aws-sdk/events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="], - - "aws-sdk/uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="], - "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], - "bl/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], "body-parser/qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], - "buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "builder-util-runtime/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "c12/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], @@ -5676,6 +5700,8 @@ "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "db0/drizzle-orm": ["drizzle-orm@1.0.0-beta.19-d95b7a4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-bZZKKeoRKrMVU6zKTscjrSH0+WNb1WEi3N0Jl4wEyQ7aQpTgHzdYY6IJQ1P0M74HuSJVeX4UpkFB/S6dtqLEJg=="], + "defaults/clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], "dir-compare/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], @@ -5710,8 +5736,6 @@ "engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], - "es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "esbuild-plugin-copy/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], @@ -5814,30 +5838,18 @@ "opencode/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], + "opencode/@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="], + "opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], "opencode-gitlab-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], "opencode-poe-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], - "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], - - "opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="], - - "opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="], - - "opencontrol/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], - - "opencontrol/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="], - "openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], "openid-client/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], - "opentui-spinner/@opentui/core": ["@opentui/core@0.2.7", "", { "dependencies": { "bun-ffi-structs": "0.2.2", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.2.7", "@opentui/core-darwin-x64": "0.2.7", "@opentui/core-linux-arm64": "0.2.7", "@opentui/core-linux-x64": "0.2.7", "@opentui/core-win32-arm64": "0.2.7", "@opentui/core-win32-x64": "0.2.7" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-cnN6JcaGC7SeQzobBy/CHzqUAQFtypazuw1CjQBo7WwoOiLMGubt9W5FXeF0zIrSxH2Ed6NLWhPYRg7SD4629Q=="], - - "opentui-spinner/@opentui/solid": ["@opentui/solid@0.2.7", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.2.7", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-nlkx9HvuWaHtc5A8eUEAPNi+5+37LZS3ln73WRmtT5xin8LnQf+yhwopqGgPSnLq1ODLwhkKRdr/9JCDr2j7Bg=="], - "ora/bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], "ora/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -5880,8 +5892,6 @@ "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - "readdir-glob/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], "restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], @@ -5892,10 +5902,6 @@ "router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], - "safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - - "safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], @@ -5908,8 +5914,6 @@ "shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="], - "sitemap/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="], @@ -5952,8 +5956,6 @@ "unused-filename/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], - "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "venice-ai-sdk-provider/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="], "vite-plugin-icons-spritesheet/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], @@ -5972,8 +5974,6 @@ "vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], - "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -5982,8 +5982,6 @@ "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="], "yaml-language-server/yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="], @@ -6048,6 +6046,36 @@ "@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-endpoints": "^3.3.4", "tslib": "^2.6.2" } }, "sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg=="], + "@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.24", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-V8z5YcDPfsvzrBlj0xR1vhRtocblhYbqdreCJB/voGd4Sr5zjNAeWxexbnqVtskTJe0vFb5KMqbSL++ePl+zRw=="], + + "@aws-sdk/client-lambda/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="], + + "@aws-sdk/client-lambda/@aws-sdk/core/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.39", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-env": "^3.972.37", "@aws-sdk/credential-provider-http": "^3.972.39", "@aws-sdk/credential-provider-login": "^3.972.41", "@aws-sdk/credential-provider-process": "^3.972.37", "@aws-sdk/credential-provider-sso": "^3.972.41", "@aws-sdk/credential-provider-web-identity": "^3.972.41", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + + "@aws-sdk/client-lambda/@aws-sdk/types/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + + "@aws-sdk/client-lambda/@smithy/core/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + + "@aws-sdk/client-lambda/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + + "@aws-sdk/client-lambda/@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw=="], "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww=="], @@ -6218,8 +6246,6 @@ "@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], - "@azure/core-http/xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], - "@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], "@azure/identity/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], @@ -6532,14 +6558,10 @@ "babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "crc/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], @@ -6582,6 +6604,8 @@ "lazystream/readable-stream/core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + "lazystream/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -6596,34 +6620,6 @@ "opencode-poe-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], - "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], - - "opencontrol/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], - - "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], - - "opencontrol/@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], - - "opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - - "opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - - "opentui-spinner/@opentui/core/@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.2.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CAy6cL3byz2Xf6gFiJHBpcnsp/2ADEWLLOUokVypOyPLcy8GY3sPzlA4pkAjVGQMYQhDj+Y3+SXz4uTLt4AETg=="], - - "opentui-spinner/@opentui/core/@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.2.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-K06h333rMkC9cyMJr/VvcRK3ik81Admd8ZsES5uf5YXWPdYhXGf75I1T8mKIThhUmoFLb8R5xqfuPmoocsjM7Q=="], - - "opentui-spinner/@opentui/core/@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.2.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-iYWGTztbdG9yYSB5Alxuo0dWAmkWQR0+/paNWUyPOocjigmKgMmACDtHgYqa7sxkIcWgmXljt/f8rgXDG4wdMg=="], - - "opentui-spinner/@opentui/core/@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.2.7", "", { "os": "linux", "cpu": "x64" }, "sha512-tymBCfYbsDRfHQNXsolkFfaTEIDhemD4+1ZovUztQd7i+0Ggnu9WbPN1SNCiRz6PjrlaNeQzZE3Wl8FfVdw/cw=="], - - "opentui-spinner/@opentui/core/@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.2.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-XLPJWdT8QOukrYDkpIng6+uNUlF66ByXcQlC3qA9JbrUTBetZhgXs8Q2jEjRfc+Ty3uh1iRSA6PgJGbbOK/f4Q=="], - - "opentui-spinner/@opentui/core/@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.2.7", "", { "os": "win32", "cpu": "x64" }, "sha512-CzVGEfqysVk8Hxcj0RDv/DtXIM6iZmbmr23kW7y8CJMPtmV1gmKI4D9abVjynWJnGbaSBnDi43mgZnGMgOdyEg=="], - - "opentui-spinner/@opentui/core/diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], - - "opentui-spinner/@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], - "ora/bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "ora/bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], @@ -6636,8 +6632,6 @@ "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], - "readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], @@ -6756,6 +6750,18 @@ "@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], + "@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="], "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg=="], @@ -6952,32 +6958,6 @@ "js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - - "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], - - "opencontrol/@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], - - "opencontrol/@modelcontextprotocol/sdk/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - - "opencontrol/@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], - - "opencontrol/@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], - - "opencontrol/@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - - "opencontrol/@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - - "opencontrol/@modelcontextprotocol/sdk/express/send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], - - "opencontrol/@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], - - "opencontrol/@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], - - "opentui-spinner/@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "ora/bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], @@ -7000,6 +6980,16 @@ "@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], + "@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="], + + "@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], @@ -7074,8 +7064,6 @@ "js-beautify/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "opencontrol/@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], @@ -7084,6 +7072,12 @@ "tw-to-css/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="], + + "@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="], + "@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], "@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], diff --git a/nix/hashes.json b/nix/hashes.json index 2a78095f84..592b0a9dc1 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-Ucvyzyq+oYvWglkeowSvb0LgDzkAvaSdq0CdA6jgN6U=", - "aarch64-linux": "sha256-SERwZvvN6P8/OwNolHmC0KU9H5laVQm+FD/NNKauZA8=", - "aarch64-darwin": "sha256-I1ABwMHkTAntlYyg43w0cW8iPYfZa9MT0In2C7plB5g=", - "x86_64-darwin": "sha256-degJTL0RG7QQO8/USgIF//ya7oNmwChTmAoJcpXbIp0=" + "x86_64-linux": "sha256-1RiaZQHzIhdtcOJUMsLagpP+nBBL/Qu6zQgrAXMHDCI=", + "aarch64-linux": "sha256-5QZhtkWuNpY/qUxlKRHcGbILOAVnuyzu+h8VDIuMQcU=", + "aarch64-darwin": "sha256-9w3QA22XNc1itGLyhikYU90xGH/iLUUM+SSGXla7lhw=", + "x86_64-darwin": "sha256-cSYiyhhSqIYiTeK1uWHDkHbYstQYD5jEB7JaYjWjgi4=" } } diff --git a/package.json b/package.json index aa64605532..d8e49ad006 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "AI-powered development tool", "private": true, "type": "module", - "packageManager": "bun@1.3.13", + "packageManager": "bun@1.3.14", "scripts": { "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", "dev:storybook": "bun --cwd packages/storybook storybook", @@ -25,15 +25,15 @@ "packages/sdk/js" ], "catalog": { - "@effect/opentelemetry": "4.0.0-beta.65", - "@effect/platform-node": "4.0.0-beta.65", + "@effect/opentelemetry": "4.0.0-beta.66", + "@effect/platform-node": "4.0.0-beta.66", "@npmcli/arborist": "9.4.0", "@types/bun": "1.3.14", "@types/cross-spawn": "6.0.6", "@octokit/rest": "22.0.0", "@hono/zod-validator": "0.4.2", - "@opentui/core": "0.2.11", - "@opentui/solid": "0.2.11", + "@opentui/core": "0.2.15", + "@opentui/solid": "0.2.15", "ulid": "3.0.1", "@kobalte/core": "0.13.11", "@types/luxon": "3.7.1", @@ -49,9 +49,9 @@ "@tailwindcss/vite": "4.1.11", "diff": "8.0.4", "dompurify": "3.4.2", - "drizzle-kit": "1.0.0-beta.19-d95b7a4", - "drizzle-orm": "1.0.0-beta.19-d95b7a4", - "effect": "4.0.0-beta.65", + "drizzle-kit": "1.0.0-rc.2", + "drizzle-orm": "1.0.0-rc.2", + "effect": "4.0.0-beta.66", "ai": "6.0.168", "cross-spawn": "7.0.6", "hono": "4.12.12", @@ -70,7 +70,7 @@ "shiki": "3.20.0", "solid-list": "0.3.0", "tailwindcss": "4.1.11", - "virtua": "0.42.3", + "virtua": "0.49.1", "vite": "7.3.2", "@solidjs/meta": "0.29.4", "@solidjs/router": "0.15.4", @@ -78,7 +78,8 @@ "solid-js": "1.9.12", "vite-plugin-solid": "2.11.10", "@lydell/node-pty": "1.2.0-beta.10", - "@opentui/keymap": "0.2.11" + "@opentui/keymap": "0.2.15", + "@effect/sql-sqlite-bun": "4.0.0-beta.66" } }, "devDependencies": { @@ -92,7 +93,7 @@ "oxlint-tsgolint": "0.21.0", "prettier": "3.6.2", "semver": "^7.6.0", - "sst": "3.18.10", + "sst": "4.13.1", "turbo": "2.9.14", "@types/bun": "catalog:", "@changesets/changelog-github": "^0.5.1", @@ -151,8 +152,9 @@ "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch", "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", + "@ai-sdk/xai@3.0.82": "patches/@ai-sdk%2Fxai@3.0.82.patch", "mammoth@1.12.0": "patches/mammoth@1.12.0.patch" }, - "version": "7.3.42", + "version": "7.3.46", "peerDependencies": {} } diff --git a/packages/containers/bun-node/Dockerfile b/packages/containers/bun-node/Dockerfile index d6f4729bf5..635ac62f6b 100644 --- a/packages/containers/bun-node/Dockerfile +++ b/packages/containers/bun-node/Dockerfile @@ -4,7 +4,7 @@ FROM ${REGISTRY}/build/base:24.04 SHELL ["/bin/bash", "-lc"] ARG NODE_VERSION=24.4.0 -ARG BUN_VERSION=1.3.13 +ARG BUN_VERSION=1.3.14 ENV BUN_INSTALL=/opt/bun ENV PATH=/opt/bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/packages/core/package.json b/packages/core/package.json index 5c913f0b26..bfbec60f89 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.42", + "version": "7.3.46", "name": "@opencode-ai/core", "type": "module", "license": "MIT", @@ -49,7 +49,7 @@ "@ai-sdk/amazon-bedrock": "4.0.96", "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/azure": "3.0.49", - "@ai-sdk/cerebras": "2.0.41", + "@ai-sdk/cerebras": "2.0.54", "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", @@ -58,17 +58,17 @@ "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", - "@ai-sdk/openai-compatible": "2.0.41", + "@ai-sdk/openai-compatible": "2.0.48", "@ai-sdk/perplexity": "3.0.26", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@ai-sdk/togetherai": "2.0.41", "@ai-sdk/vercel": "2.0.39", - "@ai-sdk/xai": "3.0.82", + "@ai-sdk/xai": "3.0.92", "@aws-sdk/credential-providers": "3.993.0", - "@openrouter/ai-sdk-provider": "2.8.1", + "@openrouter/ai-sdk-provider": "2.9.0", "ai-gateway-provider": "3.1.2", - "gitlab-ai-provider": "6.6.0", + "gitlab-ai-provider": "6.7.0", "google-auth-library": "10.5.0", "immer": "11.1.4", "venice-ai-sdk-provider": "2.0.1" diff --git a/packages/core/src/account.ts b/packages/core/src/account.ts new file mode 100644 index 0000000000..768971c9c7 --- /dev/null +++ b/packages/core/src/account.ts @@ -0,0 +1,319 @@ +import path from "path" +import { Effect, Layer, Option, Schema, Context, SynchronizedRef } from "effect" +import { Identifier } from "./util/identifier" +import { NonNegativeInt, withStatics } from "./schema" +import { Global } from "./global" +import { AppFileSystem } from "./filesystem" +import { EventV2 } from "./event" + +export const ID = Schema.String.pipe( + Schema.brand("AccountV2.ID"), + withStatics((schema) => ({ create: () => schema.make("acc_" + Identifier.ascending()) })), +) +export type ID = typeof ID.Type + +export const ServiceID = Schema.String.pipe(Schema.brand("ServiceID")) +export type ServiceID = typeof ServiceID.Type + +export class OAuthCredential extends Schema.Class("AccountV2.OAuthCredential")({ + type: Schema.Literal("oauth"), + refresh: Schema.String, + access: Schema.String, + expires: NonNegativeInt, +}) {} + +export class ApiKeyCredential extends Schema.Class("AccountV2.ApiKeyCredential")({ + type: Schema.Literal("api"), + key: Schema.String, + metadata: Schema.optional(Schema.Record(Schema.String, Schema.String)), +}) {} + +export const Credential = Schema.Union([OAuthCredential, ApiKeyCredential]) + .pipe(Schema.toTaggedUnion("type")) + .annotate({ + identifier: "AccountV2.Credential", + }) +export type Credential = Schema.Schema.Type + +export class Info extends Schema.Class("AccountV2.Info")({ + id: ID, + serviceID: ServiceID, + description: Schema.String, + credential: Credential, +}) {} + +export class FileWriteError extends Schema.TaggedErrorClass()("AccountV2.FileWriteError", { + operation: Schema.Union([Schema.Literal("migrate"), Schema.Literal("write")]), + cause: Schema.Defect, +}) {} + +export type Error = FileWriteError + +export const Event = { + Added: EventV2.define({ + type: "account.added", + schema: { + account: Info, + }, + }), + Removed: EventV2.define({ + type: "account.removed", + schema: { + account: Info, + }, + }), + Switched: EventV2.define({ + type: "account.switched", + schema: { + serviceID: ServiceID, + from: Schema.optional(ID), + to: Schema.optional(ID), + }, + }), +} + +interface Writable { + version: 2 + accounts: Record + active: Record +} + +const decodeV1 = Schema.decodeUnknownOption(Schema.Record(Schema.String, Credential)) + +function migrate(old: Record): Writable { + const accounts: Record = {} + const active: Record = {} + for (const [serviceID, value] of Object.entries(old)) { + const decoded = Option.getOrElse(decodeV1({ [serviceID]: value }), () => ({})) + const parsed = (decoded as Record)[serviceID] + if (!parsed) continue + const id = Identifier.ascending() + const account = ID.make(id) + const brandedServiceID = ServiceID.make(serviceID) + accounts[id] = new Info({ + id: account, + serviceID: brandedServiceID, + description: "default", + credential: parsed, + }) + active[brandedServiceID] = account + } + return { version: 2, accounts, active } +} + +export interface Interface { + readonly get: (id: ID) => Effect.Effect + readonly all: () => Effect.Effect + readonly create: (input: { + serviceID: ServiceID + credential: Credential + description?: string + }) => Effect.Effect + readonly update: (id: ID, updates: Partial>) => Effect.Effect + readonly remove: (id: ID) => Effect.Effect + readonly activate: (id: ID) => Effect.Effect + readonly active: (serviceID: ServiceID) => Effect.Effect + readonly forService: (serviceID: ServiceID) => Effect.Effect +} + +export class Service extends Context.Service()("@opencode/v2/Account") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const fsys = yield* AppFileSystem.Service + const global = yield* Global.Service + const events = yield* EventV2.Service + const file = path.join(global.data, "account.json") + const legacyFile = path.join(global.data, "auth.json") + + const writeMigrated = Effect.fnUntraced(function* (raw: Record) { + const migrated = migrate(raw) + yield* fsys + .writeJson(file, migrated, 0o600) + .pipe(Effect.mapError((cause) => new FileWriteError({ operation: "migrate", cause }))) + return migrated + }) + + const parseAuthContent = () => { + try { + return JSON.parse(process.env.KILO_AUTH_CONTENT ?? "") + } catch {} + } + + const load: () => Effect.Effect = Effect.fnUntraced(function* () { + if (process.env.KILO_AUTH_CONTENT) { + const raw = parseAuthContent() + if (raw && typeof raw === "object") { + if ("version" in raw && raw.version === 2) return raw as Writable + return yield* writeMigrated(raw as Record) + } + return { version: 2, accounts: {}, active: {} } + } + + const legacy = yield* fsys.readJson(legacyFile).pipe(Effect.orElseSucceed(() => null)) + if (legacy && typeof legacy === "object") return yield* writeMigrated(legacy as Record) + + const raw = yield* fsys.readJson(file).pipe(Effect.orElseSucceed(() => null)) + + if (raw && typeof raw === "object") { + if ("version" in raw && raw.version === 2) return raw as Writable + return yield* writeMigrated(raw as Record) + } + + return { version: 2, accounts: {}, active: {} } + }) + + const write = (data: Writable) => + fsys + .writeJson(file, data, 0o600) + .pipe(Effect.mapError((cause) => new FileWriteError({ operation: "write", cause }))) + + const state = SynchronizedRef.makeUnsafe( + yield* load().pipe(Effect.orElseSucceed((): Writable => ({ version: 2, accounts: {}, active: {} }))), + ) + + const activate = Effect.fn("AccountV2.activate")(function* (id: ID) { + const data = yield* SynchronizedRef.get(state) + const account = data.accounts[id] + if (!account) return + const activated = yield* SynchronizedRef.modifyEffect( + state, + Effect.fnUntraced(function* (data) { + const nextAccount = data.accounts[id] + if (!nextAccount) return [undefined, data] as const + + const next = { ...data, active: { ...data.active, [nextAccount.serviceID]: id } } + yield* write(next) + return [{ serviceID: nextAccount.serviceID, from: data.active[nextAccount.serviceID], to: id }, next] as const + }), + ) + if (activated) yield* events.publish(Event.Switched, activated) + }) + + const result: Interface = { + get: Effect.fn("AccountV2.get")(function* (id) { + return (yield* SynchronizedRef.get(state)).accounts[id] + }), + + all: Effect.fn("AccountV2.all")(function* () { + return Object.values((yield* SynchronizedRef.get(state)).accounts) + }), + + active: Effect.fn("AccountV2.active")(function* (serviceID) { + const data = yield* SynchronizedRef.get(state) + return ( + data.accounts[data.active[serviceID]] ?? Object.values(data.accounts).find((a) => a.serviceID === serviceID) + ) + }), + + forService: Effect.fn("AccountV2.list")(function* (serviceID) { + return Object.values((yield* SynchronizedRef.get(state)).accounts).filter((a) => a.serviceID === serviceID) + }), + + create: Effect.fn("AccountV2.add")(function* (input) { + const id = ID.make(Identifier.ascending()) + const account = new Info({ + id, + serviceID: input.serviceID, + description: input.description ?? "default", + credential: input.credential, + }) + const added = yield* SynchronizedRef.modifyEffect( + state, + Effect.fnUntraced(function* (data) { + const next = { + ...data, + accounts: { ...data.accounts, [account.id]: account }, + active: { ...data.active, [account.serviceID]: account.id }, + } + + yield* write(next) + return [ + { + account, + switched: { serviceID: account.serviceID, from: data.active[account.serviceID], to: account.id }, + }, + next, + ] as const + }), + ) + yield* events.publish(Event.Added, { account: added.account }) + yield* events.publish(Event.Switched, added.switched) + return added.account + }), + + update: Effect.fn("AccountV2.update")(function* (id, updates) { + const existing = (yield* SynchronizedRef.get(state)).accounts[id] + if (!existing) return + yield* SynchronizedRef.modifyEffect( + state, + Effect.fnUntraced(function* (data) { + if (!data.accounts[id]) return [undefined, data] as const + + const next = { + ...data, + accounts: { + ...data.accounts, + [id]: new Info({ + id, + serviceID: existing.serviceID, + description: updates.description ?? existing.description, + credential: updates.credential ?? existing.credential, + }), + }, + } + + yield* write(next) + return [undefined, next] as const + }), + ) + }), + + remove: Effect.fn("AccountV2.remove")(function* (id) { + const removed = yield* SynchronizedRef.modifyEffect( + state, + Effect.fnUntraced(function* (data) { + const accounts = { ...data.accounts } + const active = { ...data.active } + const removed = accounts[id] + if (!removed) return [undefined, data] as const + const wasActive = active[removed.serviceID] === id + delete accounts[id] + const replacement = Object.values(accounts).find((account) => account.serviceID === removed.serviceID) + if (wasActive) { + if (replacement) active[removed.serviceID] = replacement.id + else delete active[removed.serviceID] + } + + const next = { ...data, accounts, active } + yield* write(next) + return [ + { + account: removed, + switched: wasActive ? { serviceID: removed.serviceID, from: id, to: replacement?.id } : undefined, + }, + next, + ] as const + }), + ) + if (removed) { + yield* events.publish(Event.Removed, { account: removed.account }) + if (removed.switched) yield* events.publish(Event.Switched, removed.switched) + } + }), + + activate, + } + + return Service.of(result) + }), +) + +export const defaultLayer = layer.pipe( + Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(Global.defaultLayer), + Layer.provide(EventV2.defaultLayer), +) + +export * as AccountV2 from "./account" diff --git a/packages/core/src/agent.ts b/packages/core/src/agent.ts new file mode 100644 index 0000000000..7f4456c59f --- /dev/null +++ b/packages/core/src/agent.ts @@ -0,0 +1,147 @@ +export * as AgentV2 from "./agent" + +import { Context, Effect, HashMap, Layer, Option, Order, pipe, Schema, Array } from "effect" +import { produce, type Draft } from "immer" +import { ModelV2 } from "./model" +import { PermissionV2 } from "./permission" +import { PluginV2 } from "./plugin" +import { ProviderV2 } from "./provider" + +export const ID = Schema.String.pipe(Schema.brand("AgentV2.ID")) +export type ID = typeof ID.Type + +export const Mode = Schema.Literals(["subagent", "primary", "all"]).annotate({ identifier: "AgentV2.Mode" }) +export type Mode = typeof Mode.Type + +export const Info = Schema.Struct({ + name: ID, + description: Schema.optional(Schema.String), + mode: Mode, + hidden: Schema.Boolean.pipe(Schema.optional), + color: Schema.String.pipe(Schema.optional), + permission: PermissionV2.Ruleset, + model: ModelV2.Ref.pipe(Schema.optional), + system: Schema.String.pipe(Schema.optional), + options: ProviderV2.Options.pipe(Schema.optional), + steps: Schema.Int.pipe(Schema.optional), +}).annotate({ identifier: "AgentV2.Info" }) +export type Info = typeof Info.Type + +export class NotFoundError extends Schema.TaggedErrorClass()("AgentV2.NotFound", { + agent: ID, +}) {} + +export class InvalidDefaultError extends Schema.TaggedErrorClass()("AgentV2.InvalidDefault", { + agent: ID, + reason: Schema.Literals(["missing", "subagent", "hidden"]), +}) {} + +export class NoDefaultError extends Schema.TaggedErrorClass()("AgentV2.NoDefault", {}) {} + +export interface Interface { + readonly get: (agent: ID) => Effect.Effect + readonly list: () => Effect.Effect + readonly update: (agent: ID, fn: (agent: Draft) => void) => Effect.Effect + readonly remove: (agent: ID) => Effect.Effect + readonly defaultInfo: () => Effect.Effect + readonly defaultAgent: () => Effect.Effect + readonly setDefault: (agent: ID) => Effect.Effect +} + +export class Service extends Context.Service()("@opencode/v2/Agent") {} + +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + let agents = HashMap.empty() + let defaultAgent: ID | undefined + + const result: Interface = { + get: Effect.fn("AgentV2.get")(function* (agent) { + const match = HashMap.get(agents, agent) + if (!match.valueOrUndefined) return yield* new NotFoundError({ agent }) + return match.value + }), + + list: Effect.fn("AgentV2.list")(function* () { + return pipe( + HashMap.toValues(agents), + Array.sortWith((agent) => agent.name, Order.String), + ) + }), + + update: Effect.fnUntraced(function* (agent, fn) { + const next = produce( + HashMap.get(agents, agent).pipe( + Option.getOrElse( + () => + ({ + name: agent, + mode: "all", + permission: [], + options: { + headers: {}, + body: {}, + aisdk: { + provider: {}, + request: {}, + }, + }, + }) satisfies Info, + ), + ), + fn, + ) + const updated = yield* plugin.trigger("agent.update", {}, { agent: next, cancel: false }) + if (updated.cancel) return + agents = HashMap.set(agents, agent, { ...updated.agent, name: agent }) + }), + + remove: Effect.fn("AgentV2.remove")(function* (agent) { + const existing = Option.getOrUndefined(HashMap.get(agents, agent)) + if (!existing) return + if ((yield* plugin.trigger("agent.remove", { agent: existing }, { cancel: false })).cancel) return + agents = HashMap.remove(agents, agent) + if (defaultAgent === agent) defaultAgent = undefined + }), + + defaultInfo: Effect.fn("AgentV2.defaultInfo")(function* () { + const updated = yield* plugin.trigger("agent.default", {}, { agent: defaultAgent }) + const selected = updated.agent + if (selected) { + const agent = yield* result + .get(selected) + .pipe( + Effect.catchTag("AgentV2.NotFound", () => + Effect.fail(new InvalidDefaultError({ agent: selected, reason: "missing" })), + ), + ) + if (agent.mode === "subagent") return yield* new InvalidDefaultError({ agent: selected, reason: "subagent" }) + if (agent.hidden === true) return yield* new InvalidDefaultError({ agent: selected, reason: "hidden" }) + return agent + } + + const visible = pipe( + yield* result.list(), + Array.findFirst((agent) => agent.mode !== "subagent" && agent.hidden !== true), + ) + if (Option.isSome(visible)) return visible.value + return yield* new NoDefaultError() + }), + + defaultAgent: Effect.fn("AgentV2.defaultAgent")(function* () { + return (yield* result.defaultInfo()).name + }), + + setDefault: Effect.fn("AgentV2.setDefault")(function* (agent) { + yield* result.get(agent) + defaultAgent = agent + }), + } + + return Service.of(result) + }), +) + +export const defaultLayer = layer.pipe(Layer.provide(PluginV2.defaultLayer)) diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts deleted file mode 100644 index ad9a1858c4..0000000000 --- a/packages/core/src/auth.ts +++ /dev/null @@ -1,264 +0,0 @@ -import path from "path" -import { Effect, Layer, Option, Schema, Context, SynchronizedRef } from "effect" -import { Identifier } from "./util/identifier" -import { NonNegativeInt, withStatics } from "./schema" -import { Global } from "./global" -import { AppFileSystem } from "./filesystem" - -export const OAUTH_DUMMY_KEY = "opencode-oauth-dummy-key" - -const AccountID = Schema.String.pipe( - Schema.brand("AccountID"), - withStatics((schema) => ({ create: () => schema.make("acc_" + Identifier.ascending()) })), -) -export type AccountID = typeof AccountID.Type - -export const ServiceID = Schema.String.pipe(Schema.brand("ServiceID")) -export type ServiceID = typeof ServiceID.Type - -export class OAuthCredential extends Schema.Class("AuthV2.OAuthCredential")({ - type: Schema.Literal("oauth"), - refresh: Schema.String, - access: Schema.String, - expires: NonNegativeInt, -}) {} - -export class ApiKeyCredential extends Schema.Class("AuthV2.ApiKeyCredential")({ - type: Schema.Literal("api"), - key: Schema.String, - metadata: Schema.optional(Schema.Record(Schema.String, Schema.String)), -}) {} - -export const Credential = Schema.Union([OAuthCredential, ApiKeyCredential]) - .pipe(Schema.toTaggedUnion("type")) - .annotate({ - identifier: "AuthV2.Credential", - }) -export type Credential = Schema.Schema.Type - -export class Account extends Schema.Class("AuthV2.Account")({ - id: AccountID, - serviceID: ServiceID, - description: Schema.String, - credential: Credential, -}) {} - -export class AuthFileWriteError extends Schema.TaggedErrorClass()("AuthV2.FileWriteError", { - operation: Schema.Union([Schema.Literal("migrate"), Schema.Literal("write")]), - cause: Schema.Defect, -}) {} - -export type AuthError = AuthFileWriteError - -interface Writable { - version: 2 - accounts: Record - active: Record -} - -const decodeV1 = Schema.decodeUnknownOption(Schema.Record(Schema.String, Credential)) - -function migrate(old: Record): Writable { - const accounts: Record = {} - const active: Record = {} - for (const [serviceID, value] of Object.entries(old)) { - const decoded = Option.getOrElse(decodeV1({ [serviceID]: value }), () => ({})) - const parsed = (decoded as Record)[serviceID] - if (!parsed) continue - const id = Identifier.ascending() - const accountID = AccountID.make(id) - const brandedServiceID = ServiceID.make(serviceID) - accounts[id] = new Account({ - id: accountID, - serviceID: brandedServiceID, - description: "default", - credential: parsed, - }) - active[brandedServiceID] = accountID - } - return { version: 2, accounts, active } -} - -export interface Interface { - readonly get: (accountID: AccountID) => Effect.Effect - readonly all: () => Effect.Effect - readonly create: (input: { - serviceID: ServiceID - credential: Credential - description?: string - active?: boolean - }) => Effect.Effect - readonly update: ( - accountID: AccountID, - updates: Partial>, - ) => Effect.Effect - readonly remove: (accountID: AccountID) => Effect.Effect - readonly activate: (accountID: AccountID) => Effect.Effect - readonly active: (serviceID: ServiceID) => Effect.Effect - readonly forService: (serviceID: ServiceID) => Effect.Effect -} - -export class Service extends Context.Service()("@opencode/v2/Auth") {} - -export const layer = Layer.effect( - Service, - Effect.gen(function* () { - const fsys = yield* AppFileSystem.Service - const global = yield* Global.Service - const file = path.join(global.data, "auth-v2.json") - const legacyFile = path.join(global.data, "auth.json") - - const writeMigrated = Effect.fnUntraced(function* (raw: Record) { - const migrated = migrate(raw) - yield* fsys - .writeJson(file, migrated, 0o600) - .pipe(Effect.mapError((cause) => new AuthFileWriteError({ operation: "migrate", cause }))) - return migrated - }) - - const parseAuthContent = () => { - try { - return JSON.parse(process.env.KILO_AUTH_CONTENT ?? "") - } catch {} - } - - const load: () => Effect.Effect = Effect.fnUntraced(function* () { - if (process.env.KILO_AUTH_CONTENT) { - const raw = parseAuthContent() - if (raw && typeof raw === "object") { - if ("version" in raw && raw.version === 2) return raw as Writable - return yield* writeMigrated(raw as Record) - } - return { version: 2, accounts: {}, active: {} } - } - - const legacy = yield* fsys.readJson(legacyFile).pipe(Effect.orElseSucceed(() => null)) - if (legacy && typeof legacy === "object") return yield* writeMigrated(legacy as Record) - - const raw = yield* fsys.readJson(file).pipe(Effect.orElseSucceed(() => null)) - - if (raw && typeof raw === "object") { - if ("version" in raw && raw.version === 2) return raw as Writable - return yield* writeMigrated(raw as Record) - } - - return { version: 2, accounts: {}, active: {} } - }) - - const write = (data: Writable) => - fsys - .writeJson(file, data, 0o600) - .pipe(Effect.mapError((cause) => new AuthFileWriteError({ operation: "write", cause }))) - - const state = SynchronizedRef.makeUnsafe(yield* load()) - - const result: Interface = { - get: Effect.fn("AuthV2.get")(function* (accountID) { - return (yield* SynchronizedRef.get(state)).accounts[accountID] - }), - - all: Effect.fn("AuthV2.all")(function* () { - return Object.values((yield* SynchronizedRef.get(state)).accounts) - }), - - active: Effect.fn("AuthV2.active")(function* (serviceID) { - const data = yield* SynchronizedRef.get(state) - return ( - data.accounts[data.active[serviceID]] ?? Object.values(data.accounts).find((a) => a.serviceID === serviceID) - ) - }), - - forService: Effect.fn("AuthV2.list")(function* (serviceID) { - return Object.values((yield* SynchronizedRef.get(state)).accounts).filter((a) => a.serviceID === serviceID) - }), - - create: Effect.fn("AuthV2.add")(function* (input) { - return yield* SynchronizedRef.modifyEffect( - state, - Effect.fnUntraced(function* (data) { - const account = new Account({ - id: AccountID.make(Identifier.ascending()), - serviceID: input.serviceID, - description: input.description ?? "default", - credential: input.credential, - }) - const next = { - ...data, - accounts: { ...data.accounts, [account.id]: account }, - active: - (input.active ?? Object.values(data.accounts).every((a) => a.serviceID !== input.serviceID)) - ? { ...data.active, [input.serviceID]: account.id } - : data.active, - } - - yield* write(next) - return [account, next] as const - }), - ) - }), - - update: Effect.fn("AuthV2.update")(function* (accountID, updates) { - yield* SynchronizedRef.modifyEffect( - state, - Effect.fnUntraced(function* (data) { - const existing = data.accounts[accountID] - if (!existing) return [undefined, data] as const - - const next = { - ...data, - accounts: { - ...data.accounts, - [accountID]: new Account({ - id: accountID, - serviceID: existing.serviceID, - description: updates.description ?? existing.description, - credential: updates.credential ?? existing.credential, - }), - }, - } - - yield* write(next) - return [undefined, next] as const - }), - ) - }), - - remove: Effect.fn("AuthV2.remove")(function* (accountID) { - yield* SynchronizedRef.modifyEffect( - state, - Effect.fnUntraced(function* (data) { - const accounts = { ...data.accounts } - const active = { ...data.active } - if (accounts[accountID] && active[accounts[accountID].serviceID] === accountID) - delete active[accounts[accountID].serviceID] - delete accounts[accountID] - - const next = { ...data, accounts, active } - yield* write(next) - return [undefined, next] as const - }), - ) - }), - - activate: Effect.fn("AuthV2.activate")(function* (accountID) { - yield* SynchronizedRef.modifyEffect( - state, - Effect.fnUntraced(function* (data) { - const account = data.accounts[accountID] - if (!account) return [undefined, data] as const - - const next = { ...data, active: { ...data.active, [account.serviceID]: accountID } } - yield* write(next) - return [undefined, next] as const - }), - ) - }), - } - - return Service.of(result) - }), -) - -export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Global.defaultLayer)) - -export * as AuthV2 from "./auth" diff --git a/packages/core/src/catalog.ts b/packages/core/src/catalog.ts index d27f17bfb8..2bbd7bc49b 100644 --- a/packages/core/src/catalog.ts +++ b/packages/core/src/catalog.ts @@ -1,6 +1,6 @@ export * as Catalog from "./catalog" -import { Context, Effect, HashMap, Layer, Option, Order, pipe, Schema, Array } from "effect" +import { Context, Effect, HashMap, Layer, Option, Order, pipe, Schema, Array, Scope, Stream } from "effect" import { produce, type Draft } from "immer" import { ModelV2 } from "./model" import { PluginV2 } from "./plugin" @@ -8,9 +8,9 @@ import { ProviderV2 } from "./provider" import { Location } from "./location" import { EventV2 } from "./event" -type ProviderRecord = { +export type ProviderRecord = { provider: ProviderV2.Info - models: HashMap.HashMap + models: Map } export class ProviderNotFoundError extends Schema.TaggedErrorClass()( @@ -34,10 +34,26 @@ export const Event = { }), } +export type Context = { + data: readonly ProviderRecord[] + updateProvider: (providerID: ProviderV2.ID, fn: (provider: Draft) => void) => void + updateModel: (providerID: ProviderV2.ID, modelID: ModelV2.ID, fn: (model: Draft) => void) => void + provider: { + update: (providerID: ProviderV2.ID, fn: (provider: Draft) => void) => void + remove: (providerID: ProviderV2.ID) => void + } + model: { + update: (providerID: ProviderV2.ID, modelID: ModelV2.ID, fn: (model: Draft) => void) => void + remove: (providerID: ProviderV2.ID, modelID: ModelV2.ID) => void + } +} + +export type Loader = (update: (ctx: Context) => void) => Effect.Effect + export interface Interface { + readonly loader: () => Effect.Effect readonly provider: { readonly get: (providerID: ProviderV2.ID) => Effect.Effect - readonly update: (providerID: ProviderV2.ID, fn: (provider: Draft) => void) => Effect.Effect readonly all: () => Effect.Effect readonly available: () => Effect.Effect } @@ -46,11 +62,6 @@ export interface Interface { providerID: ProviderV2.ID, modelID: ModelV2.ID, ) => Effect.Effect - readonly update: ( - providerID: ProviderV2.ID, - modelID: ModelV2.ID, - fn: (model: Draft) => void, - ) => Effect.Effect readonly all: () => Effect.Effect readonly available: () => Effect.Effect readonly default: () => Effect.Effect> @@ -69,9 +80,11 @@ export const layer = Layer.effect( Effect.gen(function* () { yield* Location.Service let records = HashMap.empty() + let loaders: { update: (ctx: Context) => void }[] = [] let defaultModel: { providerID: ProviderV2.ID; modelID: ModelV2.ID } | undefined const plugin = yield* PluginV2.Service const events = yield* EventV2.Service + const scope = yield* Scope.Scope const resolve = (model: ModelV2.Info) => { const provider = Option.getOrThrow(HashMap.get(records, model.providerID)).provider @@ -112,29 +125,127 @@ export const layer = Layer.effect( return match.value } + const normalizeEndpoint = (item: Draft | Draft) => { + if (item.endpoint.type !== "aisdk" || typeof item.options.aisdk.provider.baseURL !== "string") return + item.endpoint.url = item.options.aisdk.provider.baseURL + delete item.options.aisdk.provider.baseURL + } + + const clone = (input: HashMap.HashMap) => + HashMap.fromIterable( + HashMap.toEntries(input).map(([key, value]) => [key, { ...value, models: new Map(value.models) }] as const), + ) + + const context = (draft: { + records: HashMap.HashMap + data: ProviderRecord[] + }): Context => { + const result: Context = { + data: draft.data, + updateProvider: (providerID, fn) => result.provider.update(providerID, fn), + updateModel: (providerID, modelID, fn) => result.model.update(providerID, modelID, fn), + provider: { + update: (providerID, fn) => { + const current = Option.getOrUndefined(HashMap.get(draft.records, providerID)) + const provider = produce(current?.provider ?? ProviderV2.Info.empty(providerID), (draft) => { + fn(draft) + normalizeEndpoint(draft) + }) + const next = { + provider, + models: current?.models ?? new Map(), + } + draft.records = HashMap.set(draft.records, providerID, next) + const index = draft.data.findIndex((item) => item.provider.id === providerID) + if (index === -1) draft.data.push(next) + else draft.data[index] = next + }, + remove: (providerID) => { + draft.records = HashMap.remove(draft.records, providerID) + const index = draft.data.findIndex((item) => item.provider.id === providerID) + if (index !== -1) draft.data.splice(index, 1) + }, + }, + model: { + update: (providerID, modelID, fn) => { + const current = Option.getOrThrow(HashMap.get(draft.records, providerID)) + const model = produce(current.models.get(modelID) ?? ModelV2.Info.empty(providerID, modelID), (draft) => { + fn(draft) + normalizeEndpoint(draft) + }) + const next = { + provider: current.provider, + models: new Map(current.models).set(modelID, new ModelV2.Info({ ...model, id: modelID, providerID })), + } + draft.records = HashMap.set(draft.records, providerID, next) + const index = draft.data.findIndex((item) => item.provider.id === providerID) + if (index === -1) draft.data.push(next) + else draft.data[index] = next + }, + remove: (providerID, modelID) => { + const current = Option.getOrUndefined(HashMap.get(draft.records, providerID)) + if (!current) return + const next = { + provider: current.provider, + models: new Map(current.models), + } + next.models.delete(modelID) + draft.records = HashMap.set(draft.records, providerID, next) + const index = draft.data.findIndex((item) => item.provider.id === providerID) + if (index !== -1) draft.data[index] = next + }, + }, + } + return result + } + + const transform = Effect.fn("CatalogV2.transform")(function* () { + const draft = { records: clone(records), data: HashMap.toValues(records) } + yield* plugin.trigger("catalog.transform", context(draft), {}) + records = draft.records + }) + + const rebuild = Effect.fn("CatalogV2.rebuild")(function* () { + const draft = { records: HashMap.empty(), data: [] as ProviderRecord[] } + for (const loader of loaders) loader.update(context(draft)) + yield* plugin.trigger("catalog.transform", context(draft), {}) + records = draft.records + }) + + yield* plugin.added().pipe( + Stream.runForEach((id) => + Effect.gen(function* () { + const draft = { records: clone(records), data: HashMap.toValues(records) } + yield* plugin.triggerFor(id, "catalog.transform", context(draft), {}) + records = draft.records + }), + ), + Effect.forkIn(scope, { startImmediately: true }), + ) + const result: Interface = { + loader: Effect.fn("CatalogV2.loader")(function* () { + const loader = { update: (_ctx: Context) => {} } + loaders = [...loaders, loader] + const scope = yield* Scope.Scope + yield* Scope.addFinalizer( + scope, + Effect.sync(() => { + loaders = loaders.filter((item) => item !== loader) + }).pipe(Effect.andThen(rebuild())), + ) + return Effect.fnUntraced(function* (update) { + loader.update = update + yield* rebuild() + }) + }), + provider: { get: Effect.fn("CatalogV2.provider.get")(function* (providerID) { const record = yield* getRecord(providerID) return record.provider }), - update: Effect.fnUntraced(function* (providerID, fn) { - const current = Option.getOrUndefined(HashMap.get(records, providerID)) - const provider = produce(current?.provider ?? ProviderV2.Info.empty(providerID), (draft) => { - fn(draft) - if (draft.endpoint.type === "aisdk" && typeof draft.options.aisdk.provider.baseURL === "string") { - draft.endpoint.url = draft.options.aisdk.provider.baseURL - delete draft.options.aisdk.provider.baseURL - } - }) - const updated = yield* plugin.trigger("provider.update", {}, { provider, cancel: false }) - records = HashMap.set(records, providerID, { - provider: updated.provider, - models: current?.models ?? HashMap.empty(), - }) - }), - all: Effect.fn("CatalogV2.provider.all")(function* () { return globalThis.Array.from(HashMap.values(records)).map((record) => record.provider) }), @@ -149,39 +260,16 @@ export const layer = Layer.effect( model: { get: Effect.fn("CatalogV2.model.get")(function* (providerID, modelID) { const record = yield* getRecord(providerID) - const model = Option.getOrUndefined(HashMap.get(record.models, modelID)) + const model = record.models.get(modelID) if (!model) return yield* new ModelNotFoundError({ providerID, modelID }) return resolve(model) }), - update: Effect.fnUntraced(function* (providerID, modelID, fn) { - const record = yield* getRecord(providerID) - const model = produce( - HashMap.get(record.models, modelID).pipe(Option.getOrElse(() => ModelV2.Info.empty(providerID, modelID))), - (draft) => { - fn(draft) - if (draft.endpoint.type === "aisdk" && typeof draft.options.aisdk.provider.baseURL === "string") { - draft.endpoint.url = draft.options.aisdk.provider.baseURL - delete draft.options.aisdk.provider.baseURL - } - }, - ) - const updated = yield* plugin.trigger("model.update", {}, { model, cancel: false }) - if (updated.cancel) return - const next = new ModelV2.Info({ ...updated.model, id: modelID, providerID }) - records = HashMap.set(records, providerID, { - provider: record.provider, - models: HashMap.set(record.models, modelID, next), - }) - yield* events.publish(Event.ModelUpdated, { model: resolve(next) }) - return - }), - all: Effect.fn("CatalogV2.model.all")(function* () { return pipe( records, HashMap.toValues, - Array.flatMap((record) => HashMap.toValues(record.models)), + Array.flatMap((record) => globalThis.Array.from(record.models.values())), Array.map(resolve), Array.sortWith((item) => item.time.released.epochMilliseconds, Order.flip(Order.Number)), ) @@ -217,12 +305,12 @@ export const layer = Layer.effect( if (!record) return Option.none() if (providerID === ProviderV2.ID.opencode) { - const gpt5Nano = Option.getOrUndefined(HashMap.get(record.models, ModelV2.ID.make("gpt-5-nano"))) + const gpt5Nano = record.models.get(ModelV2.ID.make("gpt-5-nano")) if (gpt5Nano?.enabled && gpt5Nano.status === "active") return Option.some(resolve(gpt5Nano)) } const candidates = pipe( - HashMap.toValues(record.models), + globalThis.Array.from(record.models.values()), Array.filter( (model) => model.providerID === providerID && @@ -266,4 +354,4 @@ export const layer = Layer.effect( const SMALL_MODEL_RE = /\b(nano|flash|lite|mini|haiku|small|fast)\b/ -export const defaultLayer = layer.pipe(Layer.provideMerge(EventV2.defaultLayer), Layer.provide(PluginV2.defaultLayer)) +export const defaultLayer = layer.pipe(Layer.provide(EventV2.defaultLayer), Layer.provide(PluginV2.defaultLayer)) diff --git a/packages/core/src/event.ts b/packages/core/src/event.ts index e01dc5b0d6..a4a5dd8595 100644 --- a/packages/core/src/event.ts +++ b/packages/core/src/event.ts @@ -1,3 +1,5 @@ +export * as EventV2 from "./event" + import { Context, Effect, Layer, Option, PubSub, Schema, Stream } from "effect" import { Location } from "./location" import { withStatics } from "./schema" @@ -153,5 +155,3 @@ export const layer = Layer.effect( ) export const defaultLayer = layer - -export * as EventV2 from "./event" diff --git a/packages/core/src/flag/flag.ts b/packages/core/src/flag/flag.ts index 5fb9337019..1ac32562fb 100644 --- a/packages/core/src/flag/flag.ts +++ b/packages/core/src/flag/flag.ts @@ -21,7 +21,6 @@ export const Flag = { KILO_DISABLE_PRUNE: truthy("KILO_DISABLE_PRUNE"), KILO_DISABLE_TERMINAL_TITLE: truthy("KILO_DISABLE_TERMINAL_TITLE"), KILO_SHOW_TTFD: truthy("KILO_SHOW_TTFD"), - KILO_PERMISSION: process.env["KILO_PERMISSION"], KILO_DISABLE_AUTOCOMPACT: truthy("KILO_DISABLE_AUTOCOMPACT"), KILO_DISABLE_MODELS_FETCH: truthy("KILO_DISABLE_MODELS_FETCH"), KILO_DISABLE_MOUSE: truthy("KILO_DISABLE_MOUSE"), @@ -59,6 +58,9 @@ export const Flag = { get KILO_PURE() { return truthy("KILO_PURE") }, + get KILO_PERMISSION() { + return process.env["KILO_PERMISSION"] + }, get KILO_PLUGIN_META_FILE() { return process.env["KILO_PLUGIN_META_FILE"] }, diff --git a/packages/core/src/location-layer.ts b/packages/core/src/location-layer.ts index 84dfb3dfae..c40a940430 100644 --- a/packages/core/src/location-layer.ts +++ b/packages/core/src/location-layer.ts @@ -4,9 +4,10 @@ import { Catalog } from "./catalog" import { PluginBoot } from "./plugin/boot" export class LocationServiceMap extends LayerMap.Service()("@opencode/example/LocationServiceMap", { - lookup: (ref: Location.Ref) => { - const location = Layer.succeed(Location.Service, Location.Service.of(ref)) - return Layer.mergeAll(Catalog.defaultLayer, PluginBoot.defaultLayer).pipe(Layer.provide(location)) - }, + lookup: (ref: Location.Ref) => + Layer.mergeAll(Catalog.defaultLayer, PluginBoot.defaultLayer).pipe( + Layer.provide([Layer.succeed(Location.Service, Location.Service.of(ref))]), + ), idleTimeToLive: "5 minutes", + dependencies: [], }) {} diff --git a/packages/core/src/models.ts b/packages/core/src/models-dev.ts similarity index 91% rename from packages/core/src/models.ts rename to packages/core/src/models-dev.ts index f826a50e11..d970a67a07 100644 --- a/packages/core/src/models.ts +++ b/packages/core/src/models-dev.ts @@ -7,6 +7,7 @@ import { Flock } from "./util/flock" import { Hash } from "./util/hash" import { AppFileSystem } from "./filesystem" import { InstallationChannel, InstallationVersion } from "./installation/version" +import { EventV2 } from "./event" export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"]) export type CatalogModelStatus = typeof CatalogModelStatus.Type @@ -105,6 +106,15 @@ export const Provider = Schema.Struct({ export type Provider = Schema.Schema.Type +export const Event = { + Refreshed: EventV2.define({ + type: "models-dev.refreshed", + schema: {}, + }), +} + +declare const KILO_MODELS_DEV: Record | undefined + export interface Interface { readonly get: () => Effect.Effect> readonly refresh: (force?: boolean) => Effect.Effect @@ -112,12 +122,11 @@ export interface Interface { export class Service extends Context.Service()("@opencode/ModelsDev") {} -type Requirements = AppFileSystem.Service | HttpClient.HttpClient - -export const layer: Layer.Layer = Layer.effect( +export const layer = Layer.effect( Service, Effect.gen(function* () { const fs = yield* AppFileSystem.Service + const events = yield* EventV2.Service const http = HttpClient.filterStatusOk( (yield* HttpClient.HttpClient).pipe( HttpClient.retryTransient({ @@ -157,12 +166,9 @@ export const layer: Layer.Layer = Layer.effect( Effect.map((v) => v as Record | undefined), ) - // Bundled at build time; absent in dev — `tryPromise` covers both. - const loadSnapshot = Effect.tryPromise({ - // @ts-ignore — generated at build time, may not exist in dev - try: () => import("./models-snapshot.js").then((m) => m.snapshot as Record | undefined), - catch: () => undefined, - }).pipe(Effect.catch(() => Effect.succeed(undefined))) + const loadSnapshot = Effect.sync(() => + typeof KILO_MODELS_DEV === "undefined" ? undefined : KILO_MODELS_DEV, + ) const fetchAndWrite = Effect.fn("ModelsDev.fetchAndWrite")(function* () { const text = yield* fetchApi() @@ -200,6 +206,7 @@ export const layer: Layer.Layer = Layer.effect( if (!force && (yield* fresh())) return yield* fetchAndWrite() yield* invalidate + yield* events.publish(Event.Refreshed, {}) }), ).pipe( Effect.tapCause((cause) => @@ -218,9 +225,10 @@ export const layer: Layer.Layer = Layer.effect( }), ) -export const defaultLayer: Layer.Layer = layer.pipe( +export const defaultLayer = layer.pipe( Layer.provide(FetchHttpClient.layer), Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(EventV2.defaultLayer), ) -export * as ModelsDev from "./models" +export * as ModelsDev from "./models-dev" diff --git a/packages/core/src/models-snapshot.js b/packages/core/src/models-snapshot.js deleted file mode 100644 index c582a75bdf..0000000000 --- a/packages/core/src/models-snapshot.js +++ /dev/null @@ -1,71726 +0,0 @@ -// @ts-nocheck -// Auto-generated by build.ts - do not edit -export const snapshot = { - "302ai": { - id: "302ai", - env: ["302AI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.302.ai/v1", - name: "302.AI", - doc: "https://doc.302.ai", - models: { - "qwen3-235b-a22b": { - id: "qwen3-235b-a22b", - name: "Qwen3-235B-A22B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 2.86 }, - limit: { context: 128000, output: 16384 }, - }, - "grok-4.1": { - id: "grok-4.1", - name: "grok-4.1", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10 }, - limit: { context: 200000, output: 64000 }, - }, - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax-M2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-10-26", - last_updated: "2025-10-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 1.32 }, - limit: { context: 1000000, output: 128000 }, - }, - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "grok-4-1-fast-reasoning", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 30000 }, - }, - "gemini-2.5-flash-nothink": { - id: "gemini-2.5-flash-nothink", - name: "gemini-2.5-flash-nothink", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-24", - last_updated: "2025-06-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1000000, output: 65536 }, - }, - "grok-4.20-multi-agent-beta-0309": { - id: "grok-4.20-multi-agent-beta-0309", - name: "grok-4.20-multi-agent-beta-0309", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 2000000, output: 30000 }, - }, - "kimi-k2-0905-preview": { - id: "kimi-k2-0905-preview", - name: "kimi-k2-0905-preview", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.632, output: 2.53 }, - limit: { context: 262144, output: 262144 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "claude-haiku-4-5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-16", - last_updated: "2025-10-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "claude-opus-4-5-20251101", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "gemini-2.5-flash-lite-preview-09-2025", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-26", - last_updated: "2025-09-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "qwen3-235b-a22b-instruct-2507", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1.143 }, - limit: { context: 128000, output: 65536 }, - }, - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.72, output: 3.2 }, - limit: { context: 200000, output: 131072 }, - }, - "mistral-large-2512": { - id: "mistral-large-2512", - name: "mistral-large-2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 3.3 }, - limit: { context: 128000, output: 262144 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "glm-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.286, output: 1.142 }, - limit: { context: 204800, output: 131072 }, - }, - "claude-3-5-haiku-20241022": { - id: "claude-3-5-haiku-20241022", - name: "claude-3-5-haiku-20241022", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4 }, - limit: { context: 200000, output: 8192 }, - }, - "doubao-seed-1-8-251215": { - id: "doubao-seed-1-8-251215", - name: "doubao-seed-1-8-251215", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.114, output: 0.286 }, - limit: { context: 224000, output: 64000 }, - }, - "chatgpt-4o-latest": { - id: "chatgpt-4o-latest", - name: "chatgpt-4o-latest", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-09", - release_date: "2024-08-08", - last_updated: "2024-08-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 15 }, - limit: { context: 128000, output: 16384 }, - }, - "glm-5": { - id: "glm-5", - name: "glm-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.6 }, - limit: { context: 204800, output: 131072 }, - }, - "deepseek-chat": { - id: "deepseek-chat", - name: "Deepseek-Chat", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-11-29", - last_updated: "2024-11-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 0.43 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek-v3.2-thinking": { - id: "deepseek-v3.2-thinking", - name: "DeepSeek-V3.2-Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 0.43 }, - limit: { context: 128000, output: 128000 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "claude-sonnet-4-6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-18", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 1000000, output: 64000 }, - }, - "gpt-5-thinking": { - id: "gpt-5-thinking", - name: "gpt-5-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "glm-4.7-flashx": { - id: "glm-4.7-flashx", - name: "glm-4.7-flashx", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-20", - last_updated: "2026-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0715, output: 0.429 }, - limit: { context: 200000, output: 131072 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "gemini-3-flash-preview", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen-plus": { - id: "qwen-plus", - name: "Qwen-Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 1.2 }, - limit: { context: 1000000, output: 32768 }, - }, - "grok-4.20-beta-0309-non-reasoning": { - id: "grok-4.20-beta-0309-non-reasoning", - name: "grok-4.20-beta-0309-non-reasoning", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 2000000, output: 30000 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "claude-opus-4-7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-01-31", - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "gpt-5-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "gemini-3-pro-preview", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1000000, output: 64000 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen3-max-2025-09-23": { - id: "qwen3-max-2025-09-23", - name: "qwen3-max-2025-09-23", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.86, output: 3.43 }, - limit: { context: 258048, output: 65536 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "claude-sonnet-4-5-20250929", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen-flash": { - id: "qwen-flash", - name: "Qwen-Flash", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.022, output: 0.22 }, - limit: { context: 1000000, output: 32768 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "gemini-2.5-pro", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 1000000, output: 65536 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "grok-4-1-fast-non-reasoning", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 30000 }, - }, - "claude-3-5-haiku-latest": { - id: "claude-3-5-haiku-latest", - name: "claude-3-5-haiku-latest", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-opus-4-5-20251101-thinking": { - id: "claude-opus-4-5-20251101-thinking", - name: "claude-opus-4-5-20251101-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 200000, output: 64000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "gpt-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-12", - last_updated: "2025-12-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "gpt-5.4-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-3-pro-image-preview": { - id: "gemini-3-pro-image-preview", - name: "gemini-3-pro-image-preview", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 120 }, - limit: { context: 32768, output: 64000 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "glm-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-10", - last_updated: "2026-04-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.86, output: 3.5 }, - limit: { context: 200000, output: 131072 }, - }, - "qwen-max-latest": { - id: "qwen-max-latest", - name: "Qwen-Max-Latest", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-04-03", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.343, output: 1.372 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "gpt-5.4-nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-flash-image": { - id: "gemini-2.5-flash-image", - name: "gemini-2.5-flash-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-10-08", - last_updated: "2025-10-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 30 }, - limit: { context: 32768, output: 32768 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.286, output: 1.142 }, - limit: { context: 131072, output: 98304 }, - }, - "gpt-5.4-mini-2026-03-17": { - id: "gpt-5.4-mini-2026-03-17", - name: "gpt-5.4-mini-2026-03-17", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "gemini-2.5-flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1000000, output: 65536 }, - }, - "gpt-5.2-chat-latest": { - id: "gpt-5.2-chat-latest", - name: "gpt-5.2-chat-latest", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-12", - last_updated: "2025-12-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 128000, output: 16384 }, - }, - "doubao-seed-1-6-vision-250815": { - id: "doubao-seed-1-6-vision-250815", - name: "doubao-seed-1-6-vision-250815", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.114, output: 1.143 }, - limit: { context: 256000, output: 32000 }, - }, - "gemini-3.1-flash-image-preview": { - id: "gemini-3.1-flash-image-preview", - name: "gemini-3.1-flash-image-preview", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-27", - last_updated: "2026-02-27", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.5, output: 60 }, - limit: { context: 131072, output: 32768 }, - }, - "MiniMax-M2.7-highspeed": { - id: "MiniMax-M2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4.8 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.5-x": { - id: "glm-4.5-x", - name: "glm-4.5-x", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.143, output: 2.29 }, - limit: { context: 128000, output: 16384 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 1000000, output: 131072 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "gpt-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "kimi-k2-thinking-turbo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.265, output: 9.119 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-reasoner": { - id: "deepseek-reasoner", - name: "Deepseek-Reasoner", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 0.43 }, - limit: { context: 128000, output: 128000 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "grok-4-fast-reasoning", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 30000 }, - }, - "claude-opus-4-1-20250805-thinking": { - id: "claude-opus-4-1-20250805-thinking", - name: "claude-opus-4-1-20250805-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-05-27", - last_updated: "2025-05-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 200000, output: 32000 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "glm-4.5-air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1143, output: 0.286 }, - limit: { context: 131072, output: 98304 }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "gpt-5.4-pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, cache_read: 0, cache_write: 0, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "glm-5-turbo": { - id: "glm-5-turbo", - name: "glm-5-turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.72, output: 3.2 }, - limit: { context: 200000, output: 131072 }, - }, - "qwen3-30b-a3b": { - id: "qwen3-30b-a3b", - name: "Qwen3-30B-A3B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.11, output: 1.08 }, - limit: { context: 128000, output: 8192 }, - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "claude-opus-4-5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 200000, output: 64000 }, - }, - "glm-4.5v": { - id: "glm-4.5v", - name: "GLM-4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 0.86 }, - limit: { context: 64000, output: 16384 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "glm-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.286, output: 1.142 }, - limit: { context: 204800, output: 131072 }, - }, - "claude-opus-4-6-thinking": { - id: "claude-opus-4-6-thinking", - name: "claude-opus-4-6-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-02-06", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 1000000, output: 128000 }, - }, - "gemini-2.5-flash-preview-09-2025": { - id: "gemini-2.5-flash-preview-09-2025", - name: "gemini-2.5-flash-preview-09-2025", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-26", - last_updated: "2025-09-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1000000, output: 65536 }, - }, - "claude-sonnet-4-6-thinking": { - id: "claude-sonnet-4-6-thinking", - name: "claude-sonnet-4-6-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2026-02-18", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 1000000, output: 64000 }, - }, - "glm-4.6v": { - id: "glm-4.6v", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.145, output: 0.43 }, - limit: { context: 128000, output: 32768 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "claude-opus-4-1-20250805", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "gpt-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - cache_write: 0, - context_over_200k: { input: 5, output: 22.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-5.1-chat-latest": { - id: "gpt-5.1-chat-latest", - name: "gpt-5.1-chat-latest", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "claude-haiku-4-5-20251001", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-16", - last_updated: "2025-10-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 200000, output: 64000 }, - }, - "MiniMax-M1": { - id: "MiniMax-M1", - name: "MiniMax-M1", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-16", - last_updated: "2025-06-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.132, output: 1.254 }, - limit: { context: 1000000, output: 128000 }, - }, - "gpt-5.4-nano-2026-03-17": { - id: "gpt-5.4-nano-2026-03-17", - name: "gpt-5.4-nano-2026-03-17", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-19", - last_updated: "2026-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "claude-sonnet-4-20250514", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "qwen3-coder-480b-a35b-instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.86, output: 3.43 }, - limit: { context: 262144, output: 65536 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "claude-opus-4-6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-06", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 1000000, output: 128000 }, - }, - "doubao-seed-code-preview-251028": { - id: "doubao-seed-code-preview-251028", - name: "doubao-seed-code-preview-251028", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-11-11", - last_updated: "2025-11-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 1.14 }, - limit: { context: 256000, output: 32000 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "gpt-4.1-nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1047576, output: 32768 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "deepseek-v3.2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 0.43 }, - limit: { context: 128000, output: 8192 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "gpt-5-pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-08", - last_updated: "2025-10-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, input: 272000, output: 272000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "gpt-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "claude-sonnet-4-5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "gpt-5": { - id: "gpt-5", - name: "gpt-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-4.20-beta-0309-reasoning": { - id: "grok-4.20-beta-0309-reasoning", - name: "grok-4.20-beta-0309-reasoning", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 2000000, output: 30000 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "claude-opus-4-20250514", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 200000, output: 32000 }, - }, - "glm-for-coding": { - id: "glm-for-coding", - name: "glm-for-coding", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.086, output: 0.343 }, - limit: { context: 200000, output: 131072 }, - }, - "claude-sonnet-4-5-20250929-thinking": { - id: "claude-sonnet-4-5-20250929-thinking", - name: "claude-sonnet-4-5-20250929-thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "glm-4.5-airx": { - id: "glm-4.5-airx", - name: "glm-4.5-airx", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.572, output: 1.714 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "gpt-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 1047576, output: 32768 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "kimi-k2-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.575, output: 2.3 }, - limit: { context: 262144, output: 262144 }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "gemini-2.0-flash-lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-11", - release_date: "2025-06-16", - last_updated: "2025-06-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 2000000, output: 8192 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "gpt-4.1-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6 }, - limit: { context: 1047576, output: 32768 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "grok-4-fast-non-reasoning", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 30000 }, - }, - "doubao-seed-1-6-thinking-250715": { - id: "doubao-seed-1-6-thinking-250715", - name: "doubao-seed-1-6-thinking-250715", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-15", - last_updated: "2025-07-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.121, output: 1.21 }, - limit: { context: 256000, output: 16000 }, - }, - "ministral-14b-2512": { - id: "ministral-14b-2512", - name: "ministral-14b-2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 0.33 }, - limit: { context: 128000, output: 128000 }, - }, - }, - }, - alibaba: { - id: "alibaba", - env: ["DASHSCOPE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", - name: "Alibaba", - doc: "https://www.alibabacloud.com/help/en/model-studio/models", - models: { - "qwen3-235b-a22b": { - id: "qwen3-235b-a22b", - name: "Qwen3 235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8, reasoning: 8.4 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen3.5-122b-a10b": { - id: "qwen3.5-122b-a10b", - name: "Qwen3.5 122B-A10B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-23", - last_updated: "2026-02-23", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 3.2 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 5 }, - limit: { context: 1048576, output: 65536 }, - }, - "qwen3.6-27b": { - id: "qwen3.6-27b", - name: "Qwen3.6 27B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3.5-27b": { - id: "qwen3.5-27b", - name: "Qwen3.5 27B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-23", - last_updated: "2026-02-23", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.4 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-vl-ocr": { - id: "qwen-vl-ocr", - name: "Qwen-VL OCR", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2024-10-28", - last_updated: "2025-04-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 34096, output: 4096 }, - }, - "qwen-omni-turbo-realtime": { - id: "qwen-omni-turbo-realtime", - name: "Qwen-Omni Turbo Realtime", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image", "audio"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.27, output: 1.07, input_audio: 4.44, output_audio: 8.89 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen3-8b": { - id: "qwen3-8b", - name: "Qwen3 8B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.7, reasoning: 2.1 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen3.5 397B-A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwq-plus": { - id: "qwq-plus", - name: "QwQ Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-vl-plus": { - id: "qwen-vl-plus", - name: "Qwen-VL Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-08-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.63 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-livetranslate-flash-realtime": { - id: "qwen3-livetranslate-flash-realtime", - name: "Qwen3-LiveTranslate Flash Realtime", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 10, output: 10, input_audio: 10, output_audio: 38 }, - limit: { context: 53248, output: 4096 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8, reasoning: 8.4 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen-max": { - id: "qwen-max", - name: "Qwen Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-03", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 6.4 }, - limit: { context: 32768, output: 8192 }, - }, - "qwen-plus": { - id: "qwen-plus", - name: "Qwen Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.2, reasoning: 4 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen3.6-35b-a3b": { - id: "qwen3.6-35b-a3b", - name: "Qwen3.6 35B-A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.248, output: 1.485 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-omni-turbo": { - id: "qwen-omni-turbo", - name: "Qwen-Omni Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01-19", - last_updated: "2025-03-26", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.07, output: 0.27, input_audio: 4.44, output_audio: 8.89 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen-flash": { - id: "qwen-flash", - name: "Qwen Flash", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen2-5-vl-7b-instruct": { - id: "qwen2-5-vl-7b-instruct", - name: "Qwen2.5-VL 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.05 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.276, output: 1.651, cache_read: 0.028, cache_write: 0.344 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3-omni-flash": { - id: "qwen3-omni-flash", - name: "Qwen3-Omni Flash", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.43, output: 1.66, input_audio: 3.81, output_audio: 15.11 }, - limit: { context: 65536, output: 16384 }, - }, - "qwen2-5-72b-instruct": { - id: "qwen2-5-72b-instruct", - name: "Qwen2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 5.6 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-vl-235b-a22b": { - id: "qwen3-vl-235b-a22b", - name: "Qwen3-VL 235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8, reasoning: 8.4 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen3-asr-flash": { - id: "qwen3-asr-flash", - name: "Qwen3-ASR Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-04", - release_date: "2025-09-08", - last_updated: "2025-09-08", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.035, output: 0.035 }, - limit: { context: 53248, output: 4096 }, - }, - "qwen3-next-80b-a3b-thinking": { - id: "qwen3-next-80b-a3b-thinking", - name: "Qwen3-Next 80B-A3B (Thinking)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 6 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen-mt-plus": { - id: "qwen-mt-plus", - name: "Qwen-MT Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.46, output: 7.37 }, - limit: { context: 16384, output: 8192 }, - }, - "qwen-vl-max": { - id: "qwen-vl-max", - name: "Qwen-VL Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-08", - last_updated: "2025-08-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-coder-flash": { - id: "qwen3-coder-flash", - name: "Qwen3 Coder Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen2-5-7b-instruct": { - id: "qwen2-5-7b-instruct", - name: "Qwen2.5 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.175, output: 0.7 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen2-5-14b-instruct": { - id: "qwen2-5-14b-instruct", - name: "Qwen2.5 14B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.4 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen2-5-32b-instruct": { - id: "qwen2-5-32b-instruct", - name: "Qwen2.5 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-next-80b-a3b-instruct": { - id: "qwen3-next-80b-a3b-instruct", - name: "Qwen3-Next 80B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen-plus-character-ja": { - id: "qwen-plus-character-ja", - name: "Qwen Plus Character (Japanese)", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.4 }, - limit: { context: 8192, output: 512 }, - }, - "qwen3-omni-flash-realtime": { - id: "qwen3-omni-flash-realtime", - name: "Qwen3-Omni Flash Realtime", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.52, output: 1.99, input_audio: 4.57, output_audio: 18.13 }, - limit: { context: 65536, output: 16384 }, - }, - "qwen3-vl-30b-a3b": { - id: "qwen3-vl-30b-a3b", - name: "Qwen3-VL 30B-A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8, reasoning: 2.4 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen3-vl-plus": { - id: "qwen3-vl-plus", - name: "Qwen3-VL Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.6, reasoning: 4.8 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "Qwen3-Coder 480B-A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.5, output: 7.5 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3-Coder 30B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.25 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-turbo": { - id: "qwen-turbo", - name: "Qwen Turbo", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-11-01", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.2, reasoning: 0.5 }, - limit: { context: 1000000, output: 16384 }, - }, - "qwen-mt-turbo": { - id: "qwen-mt-turbo", - name: "Qwen-MT Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.16, output: 0.49 }, - limit: { context: 16384, output: 8192 }, - }, - "qwen3.6-max-preview": { - id: "qwen3.6-max-preview", - name: "Qwen3.6 Max Preview", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.3, output: 7.8, cache_read: 0.13, cache_write: 1.625 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen2-5-omni-7b": { - id: "qwen2-5-omni-7b", - name: "Qwen2.5-Omni 7B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: true, - cost: { input: 0.1, output: 0.4, input_audio: 6.76 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4, reasoning: 2.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen2-5-vl-72b-instruct": { - id: "qwen2-5-vl-72b-instruct", - name: "Qwen2.5-VL 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.8, output: 8.4 }, - limit: { context: 131072, output: 8192 }, - }, - "qvq-max": { - id: "qvq-max", - name: "QVQ Max", - family: "qvq", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4.8 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-14b": { - id: "qwen3-14b", - name: "Qwen3 14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.4, reasoning: 4.2 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3.5-35b-a3b": { - id: "qwen3.5-35b-a3b", - name: "Qwen3.5 35B-A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-23", - last_updated: "2026-02-23", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - scaleway: { - id: "scaleway", - env: ["SCALEWAY_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.scaleway.ai/v1", - name: "Scaleway", - doc: "https://www.scaleway.com/en/docs/generative-apis/", - models: { - "qwen3-embedding-8b": { - id: "qwen3-embedding-8b", - name: "Qwen3 Embedding 8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-25-11", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 32768, output: 4096 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 2.25 }, - limit: { context: 260000, output: 16384 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 0.9 }, - limit: { context: 100000, output: 16384 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 256000, output: 16384 }, - }, - "devstral-2-123b-instruct-2512": { - id: "devstral-2-123b-instruct-2512", - name: "Devstral 2 123B Instruct (2512)", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-01-07", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 256000, output: 16384 }, - }, - "deepseek-r1-distill-llama-70b": { - id: "deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 0.9 }, - limit: { context: 32000, output: 8196 }, - }, - "pixtral-12b-2409": { - id: "pixtral-12b-2409", - name: "Pixtral 12B 2409", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09-25", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, output: 4096 }, - }, - "whisper-large-v3": { - id: "whisper-large-v3", - name: "Whisper Large v3", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2023-09", - release_date: "2023-09-01", - last_updated: "2026-03-17", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.003, output: 0 }, - limit: { context: 0, output: 8192 }, - }, - "voxtral-small-24b-2507": { - id: "voxtral-small-24b-2507", - name: "Voxtral Small 24B 2507", - family: "voxtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2026-03-17", - modalities: { input: ["text", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.35 }, - limit: { context: 32000, output: 16384 }, - }, - "gemma-3-27b-it": { - id: "gemma-3-27b-it", - name: "Gemma-3-27B-IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.5 }, - limit: { context: 40000, output: 8192 }, - }, - "bge-multilingual-gemma2": { - id: "bge-multilingual-gemma2", - name: "BGE Multilingual Gemma2", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-07-26", - last_updated: "2025-06-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8191, output: 3072 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3-Coder 30B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral-small-3.2-24b-instruct-2506": { - id: "mistral-small-3.2-24b-instruct-2506", - name: "Mistral Small 3.2 24B Instruct (2506)", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-20", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.35 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT-OSS 120B", - family: "gpt-oss", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-01-01", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral-nemo-instruct-2407": { - id: "mistral-nemo-instruct-2407", - name: "Mistral Nemo Instruct 2407", - family: "mistral-nemo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-25", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, output: 8192 }, - }, - "llama-3.1-8b-instruct": { - id: "llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, output: 16384 }, - }, - }, - }, - "nano-gpt": { - id: "nano-gpt", - env: ["NANO_GPT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://nano-gpt.com/api/v1", - name: "NanoGPT", - doc: "https://docs.nano-gpt.com", - models: { - "glm-4-flash": { - id: "glm-4-flash", - name: "GLM-4 Flash", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-08-01", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1003 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "Meta-Llama-3-1-8B-Instruct-FP8": { - id: "Meta-Llama-3-1-8B-Instruct-FP8", - name: "Llama 3.1 8B (decentralized)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.03 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "claude-opus-4-thinking:32000": { - id: "claude-opus-4-thinking:32000", - name: "Claude 4 Opus Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "gemini-2.5-pro-preview-05-06": { - id: "gemini-2.5-pro-preview-05-06", - name: "Gemini 2.5 Pro Preview 0506", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-05-06", - last_updated: "2025-05-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "grok-3-mini-fast-beta": { - id: "grok-3-mini-fast-beta", - name: "Grok 3 Mini Fast Beta", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4 }, - limit: { context: 131072, input: 131072, output: 131072 }, - }, - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax M2", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-10-25", - last_updated: "2025-10-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 1.53 }, - limit: { context: 200000, input: 200000, output: 131072 }, - }, - "command-a-reasoning-08-2025": { - id: "command-a-reasoning-08-2025", - name: "Cohere Command A (08/2025)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-22", - last_updated: "2025-08-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, input: 256000, output: 8192 }, - }, - brave: { - id: "brave", - name: "Brave (Answers)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-03-02", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 5 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "exa-research": { - id: "exa-research", - name: "Exa (Research)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-04", - last_updated: "2025-06-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 2.5 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "Llama-3.3-70B-Nova": { - id: "Llama-3.3-70B-Nova", - name: "Llama 3.3 70B Nova", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "gemini-exp-1206": { - id: "gemini-exp-1206", - name: "Gemini 2.0 Pro 1206", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.258, output: 4.998 }, - limit: { context: 2097152, input: 2097152, output: 8192 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "Claude 4.5 Opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "auto-model-basic": { - id: "auto-model-basic", - name: "Auto model (Basic)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 1000000, input: 1000000, output: 1000000 }, - }, - "jamba-mini": { - id: "jamba-mini", - name: "Jamba Mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1989, output: 0.408 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview (09/2025)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "yi-large": { - id: "yi-large", - name: "Yi Large", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3.196, output: 3.196 }, - limit: { context: 32000, input: 32000, output: 4096 }, - }, - "auto-model-premium": { - id: "auto-model-premium", - name: "Auto model (Premium)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 1000000, input: 1000000, output: 1000000 }, - }, - "azure-gpt-4o": { - id: "azure-gpt-4o", - name: "Azure gpt-4o", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 9.996 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "deepseek-v3-0324": { - id: "deepseek-v3-0324", - name: "DeepSeek Chat 0324", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "claude-3-5-haiku-20241022": { - id: "claude-3-5-haiku-20241022", - name: "Claude 3.5 Haiku", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4 }, - limit: { context: 200000, input: 200000, output: 8192 }, - }, - "doubao-seed-1-8-251215": { - id: "doubao-seed-1-8-251215", - name: "Doubao Seed 1.8", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-15", - last_updated: "2025-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.612, output: 6.12 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "doubao-seed-1-6-250615": { - id: "doubao-seed-1-6-250615", - name: "Doubao Seed 1.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-15", - last_updated: "2025-06-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.204, output: 0.51 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "ernie-x1.1-preview": { - id: "ernie-x1.1-preview", - name: "ERNIE X1.1", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-10", - last_updated: "2025-09-10", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 64000, input: 64000, output: 8192 }, - }, - "ernie-5.0-thinking-preview": { - id: "ernie-5.0-thinking-preview", - name: "Ernie 5.0 Thinking Preview", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 2 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "glm-4-air-0111": { - id: "glm-4-air-0111", - name: "GLM 4 Air 0111", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-11", - last_updated: "2025-01-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1394, output: 0.1394 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - fastgpt: { - id: "fastgpt", - name: "Web Answer", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-08-01", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 7.5, output: 7.5 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "doubao-seed-1-6-thinking-250615": { - id: "doubao-seed-1-6-thinking-250615", - name: "Doubao Seed 1.6 Thinking", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-15", - last_updated: "2025-06-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.204, output: 2.04 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "gemini-2.0-flash-001": { - id: "gemini-2.0-flash-001", - name: "Gemini 2.0 Flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.408 }, - limit: { context: 1000000, input: 1000000, output: 8192 }, - }, - "claude-opus-4-1-thinking:32000": { - id: "claude-opus-4-1-thinking:32000", - name: "Claude 4.1 Opus Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "Llama-3.3-70B-RAWMAW": { - id: "Llama-3.3-70B-RAWMAW", - name: "Llama 3.3 70B RAWMAW", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "GLM-4.5-Air-Derestricted-Steam": { - id: "GLM-4.5-Air-Derestricted-Steam", - name: "GLM 4.5 Air Derestricted Steam", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 220600, input: 220600, output: 65536 }, - }, - "claude-3-5-sonnet-20241022": { - id: "claude-3-5-sonnet-20241022", - name: "Claude 3.5 Sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 8192 }, - }, - "yi-medium-200k": { - id: "yi-medium-200k", - name: "Yi Medium 200k", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-03-01", - last_updated: "2024-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 2.499 }, - limit: { context: 200000, input: 200000, output: 4096 }, - }, - "Gemma-3-27B-ArliAI-RPMax-v3": { - id: "Gemma-3-27B-ArliAI-RPMax-v3", - name: "Gemma 3 27B RPMax v3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-03", - last_updated: "2025-07-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "phi-4-mini-instruct": { - id: "phi-4-mini-instruct", - name: "Phi 4 Mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter": { - id: "Llama-3.3+(3v3.3)-70B-TenyxChat-DaybreakStorywriter", - name: "Llama 3.3+ 70B TenyxChat DaybreakStorywriter", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "ernie-x1-32k": { - id: "ernie-x1-32k", - name: "Ernie X1 32k", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 1.32 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "deepseek-chat": { - id: "deepseek-chat", - name: "DeepSeek V3/Deepseek Chat", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "glm-z1-air": { - id: "glm-z1-air", - name: "GLM Z1 Air", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.07 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "claude-3-7-sonnet-thinking:128000": { - id: "claude-3-7-sonnet-thinking:128000", - name: "Claude 3.7 Sonnet Thinking (128K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "glm-4-air": { - id: "glm-4-air", - name: "GLM-4 Air", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-05", - last_updated: "2024-06-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "Llama-3.3-70B-MiraiFanfare": { - id: "Llama-3.3-70B-MiraiFanfare", - name: "Llama 3.3 70b Mirai Fanfare", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.493, output: 0.493 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "gemini-2.0-flash-thinking-exp-01-21": { - id: "gemini-2.0-flash-thinking-exp-01-21", - name: "Gemini 2.0 Flash Thinking 0121", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-01-21", - last_updated: "2025-01-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 1.003 }, - limit: { context: 1000000, input: 1000000, output: 8192 }, - }, - "Magistral-Small-2506": { - id: "Magistral-Small-2506", - name: "Magistral Small 2506", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.4 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "doubao-1.5-pro-32k": { - id: "doubao-1.5-pro-32k", - name: "Doubao 1.5 Pro 32k", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-22", - last_updated: "2025-01-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1343, output: 0.3349 }, - limit: { context: 32000, input: 32000, output: 8192 }, - }, - "venice-uncensored:web": { - id: "venice-uncensored:web", - name: "Venice Uncensored Web", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-01", - last_updated: "2024-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 80000, input: 80000, output: 16384 }, - }, - "glm-4": { - id: "glm-4", - name: "GLM-4", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-01-16", - last_updated: "2024-01-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 14.994 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "qwen-max": { - id: "qwen-max", - name: "Qwen 2.5 Max", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-04-03", - last_updated: "2024-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5997, output: 6.392 }, - limit: { context: 32000, input: 32000, output: 8192 }, - }, - "qwen3-vl-235b-a22b-instruct-original": { - id: "qwen3-vl-235b-a22b-instruct-original", - name: "Qwen3 VL 235B A22B Instruct Original", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.2 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "jamba-large-1.6": { - id: "jamba-large-1.6", - name: "Jamba Large 1.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.989, output: 7.99 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "qwen-plus": { - id: "qwen-plus", - name: "Qwen Plus", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3995, output: 1.2002 }, - limit: { context: 995904, input: 995904, output: 32768 }, - }, - "qwen25-vl-72b-instruct": { - id: "qwen25-vl-72b-instruct", - name: "Qwen25 VL 72b", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-10", - last_updated: "2025-05-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.69989, output: 0.69989 }, - limit: { context: 32000, input: 32000, output: 32768 }, - }, - "claude-sonnet-4-thinking:64000": { - id: "claude-sonnet-4-thinking:64000", - name: "Claude 4 Sonnet Thinking (64K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "Llama-3.3+(3.1v3.3)-70B-New-Dawn-v1.1": { - id: "Llama-3.3+(3.1v3.3)-70B-New-Dawn-v1.1", - name: "Llama 3.3+ 70B New Dawn v1.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "GLM-4.5-Air-Derestricted-Iceblink-ReExtract": { - id: "GLM-4.5-Air-Derestricted-Iceblink-ReExtract", - name: "GLM 4.5 Air Derestricted Iceblink ReExtract", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-12", - last_updated: "2025-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 131072, input: 131072, output: 98304 }, - }, - "universal-summarizer": { - id: "universal-summarizer", - name: "Universal Summarizer", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-05-01", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 30 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "claude-sonnet-4-thinking:32768": { - id: "claude-sonnet-4-thinking:32768", - name: "Claude 4 Sonnet Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "sarvan-medium": { - id: "sarvan-medium", - name: "Sarvam Medium", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "claude-3-7-sonnet-thinking:8192": { - id: "claude-3-7-sonnet-thinking:8192", - name: "Claude 3.7 Sonnet Thinking (8K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "gemini-2.5-flash-preview-05-20": { - id: "gemini-2.5-flash-preview-05-20", - name: "Gemini 2.5 Flash 0520", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 1048000, input: 1048000, output: 65536 }, - }, - "GLM-4.5-Air-Derestricted-Iceblink-v2-ReExtract": { - id: "GLM-4.5-Air-Derestricted-Iceblink-v2-ReExtract", - name: "GLM 4.5 Air Derestricted Iceblink v2 ReExtract", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-12", - last_updated: "2025-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 131072, input: 131072, output: 65536 }, - }, - "Llama-3.3-70B-Fallen-v1": { - id: "Llama-3.3-70B-Fallen-v1", - name: "Llama 3.3 70B Fallen v1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "qwen3-vl-235b-a22b-thinking": { - id: "qwen3-vl-235b-a22b-thinking", - name: "Qwen3 VL 235B A22B Thinking", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 6 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "claude-3-7-sonnet-thinking:32768": { - id: "claude-3-7-sonnet-thinking:32768", - name: "Claude 3.7 Sonnet Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-07-15", - last_updated: "2025-07-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "claude-3-7-sonnet-thinking:1024": { - id: "claude-3-7-sonnet-thinking:1024", - name: "Claude 3.7 Sonnet Thinking (1K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Claude Sonnet 4.5", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "Llama-3.3-70B-Vulpecula-R1": { - id: "Llama-3.3-70B-Vulpecula-R1", - name: "Llama 3.3 70B Vulpecula R1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "claude-sonnet-4-thinking:8192": { - id: "claude-sonnet-4-thinking:8192", - name: "Claude 4 Sonnet Thinking (8K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "Llama-3.3-70B-Ignition-v0.1": { - id: "Llama-3.3-70B-Ignition-v0.1", - name: "Llama 3.3 70B Ignition v0.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "glm-4-plus-0111": { - id: "glm-4-plus-0111", - name: "GLM 4 Plus 0111", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 9.996 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "KAT-Coder-Air-V1": { - id: "KAT-Coder-Air-V1", - name: "KAT Coder Air V1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-10-28", - last_updated: "2025-10-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.2 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "deepseek-r1-sambanova": { - id: "deepseek-r1-sambanova", - name: "DeepSeek R1 Fast", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-20", - last_updated: "2025-02-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 6.987 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek R1", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.7 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "doubao-1-5-thinking-pro-250415": { - id: "doubao-1-5-thinking-pro-250415", - name: "Doubao 1.5 Thinking Pro", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-17", - last_updated: "2025-04-17", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.4 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "sonar-pro": { - id: "sonar-pro", - name: "Perplexity Pro", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 128000 }, - }, - "Gemma-3-27B-it-Abliterated": { - id: "Gemma-3-27B-it-Abliterated", - name: "Gemma 3 27B IT Abliterated", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-03", - last_updated: "2025-07-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.42, output: 0.42 }, - limit: { context: 32768, input: 32768, output: 96000 }, - }, - "deepseek-chat-cheaper": { - id: "deepseek-chat-cheaper", - name: "DeepSeek V3/Chat Cheaper", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "gemini-2.0-pro-exp-02-05": { - id: "gemini-2.0-pro-exp-02-05", - name: "Gemini 2.0 Pro 0205", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-05", - last_updated: "2025-02-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.989, output: 7.956 }, - limit: { context: 2097152, input: 2097152, output: 8192 }, - }, - "azure-gpt-4o-mini": { - id: "azure-gpt-4o-mini", - name: "Azure gpt-4o-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1496, output: 0.595 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "Llama-3.3-70B-MS-Nevoria": { - id: "Llama-3.3-70B-MS-Nevoria", - name: "Llama 3.3 70B MS Nevoria", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "claude-opus-4-thinking": { - id: "claude-opus-4-thinking", - name: "Claude 4 Opus Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-07-15", - last_updated: "2025-07-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "Llama-3.3-70B-Sapphira-0.1": { - id: "Llama-3.3-70B-Sapphira-0.1", - name: "Llama 3.3 70B Sapphira 0.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "doubao-seed-code-preview-latest": { - id: "doubao-seed-code-preview-latest", - name: "Doubao Seed Code Preview", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "qwen-3.6-plus": { - id: "qwen-3.6-plus", - name: "Qwen 3.6 Plus", - family: "qwen3.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 2.7 }, - limit: { context: 991800, output: 65536 }, - }, - "Llama-3.3-70B-ArliAI-RPMax-v1.4": { - id: "Llama-3.3-70B-ArliAI-RPMax-v1.4", - name: "Llama 3.3 70B RPMax v1.4", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "mistral-small-31-24b-instruct": { - id: "mistral-small-31-24b-instruct", - name: "Mistral Small 31 24b Instruct", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, input: 128000, output: 131072 }, - }, - "glm-4.1v-thinking-flashx": { - id: "glm-4.1v-thinking-flashx", - name: "GLM 4.1V Thinking FlashX", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 64000, input: 64000, output: 8192 }, - }, - "hunyuan-t1-latest": { - id: "hunyuan-t1-latest", - name: "Hunyuan T1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-22", - last_updated: "2025-03-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 0.66 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "doubao-1-5-thinking-vision-pro-250428": { - id: "doubao-1-5-thinking-vision-pro-250428", - name: "Doubao 1.5 Thinking Vision Pro", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-15", - last_updated: "2025-05-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.55, output: 1.43 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "asi1-mini": { - id: "asi1-mini", - name: "ASI1 Mini", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "ernie-5.0-thinking-latest": { - id: "ernie-5.0-thinking-latest", - name: "Ernie 5.0 Thinking", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 2 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "Llama-3.3-70B-Incandescent-Malevolence": { - id: "Llama-3.3-70B-Incandescent-Malevolence", - name: "Llama 3.3 70B Incandescent Malevolence", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-Damascus-R1": { - id: "Llama-3.3-70B-Damascus-R1", - name: "Damascus R1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Gemma-3-27B-Nidum-Uncensored": { - id: "Gemma-3-27B-Nidum-Uncensored", - name: "Gemma 3 27B Nidum Uncensored", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - 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", - name: "Gemini 2.5 Flash Lite Preview (09/2025) – Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "doubao-seed-2-0-pro-260215": { - id: "doubao-seed-2-0-pro-260215", - name: "Doubao Seed 2.0 Pro", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.782, output: 3.876 }, - limit: { context: 256000, input: 256000, output: 128000 }, - }, - "gemini-3-pro-image-preview": { - id: "gemini-3-pro-image-preview", - name: "Gemini 3 Pro Image", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "Gemma-3-27B-CardProjector-v4": { - id: "Gemma-3-27B-CardProjector-v4", - name: "Gemma 3 27B CardProjector v4", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "jamba-mini-1.7": { - id: "jamba-mini-1.7", - name: "Jamba Mini 1.7", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1989, output: 0.408 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "Llama-3.3-70B-Forgotten-Safeword-3.6": { - id: "Llama-3.3-70B-Forgotten-Safeword-3.6", - name: "Llama 3.3 70B Forgotten Safeword 3.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "doubao-1-5-thinking-pro-vision-250415": { - id: "doubao-1-5-thinking-pro-vision-250415", - name: "Doubao 1.5 Thinking Pro Vision", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.4 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "gemini-2.5-pro-preview-06-05": { - id: "gemini-2.5-pro-preview-06-05", - name: "Gemini 2.5 Pro Preview 0605", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "gemini-2.0-pro-reasoner": { - id: "gemini-2.0-pro-reasoner", - name: "Gemini 2.0 Pro Reasoner", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-05", - last_updated: "2025-02-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.292, output: 4.998 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "doubao-seed-2-0-lite-260215": { - id: "doubao-seed-2-0-lite-260215", - name: "Doubao Seed 2.0 Lite", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1462, output: 0.8738 }, - limit: { context: 256000, input: 256000, output: 32000 }, - }, - "gemini-2.5-flash-lite-preview-06-17": { - id: "gemini-2.5-flash-lite-preview-06-17", - name: "Gemini 2.5 Flash Lite Preview", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "sonar-deep-research": { - id: "sonar-deep-research", - name: "Perplexity Deep Research", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-25", - last_updated: "2025-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3.4, output: 13.6 }, - limit: { context: 60000, input: 60000, output: 128000 }, - }, - "Gemma-3-27B-it": { - id: "Gemma-3-27B-it", - name: "Gemma 3 27B IT", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-GeneticLemonade-Unleashed-v3": { - id: "Llama-3.3-70B-GeneticLemonade-Unleashed-v3", - name: "Llama 3.3 70B GeneticLemonade Unleashed v3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Gemma-3-27B-Glitter": { - id: "Gemma-3-27B-Glitter", - name: "Gemma 3 27B Glitter", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1": { - id: "Llama-3.3-70B-The-Omega-Directive-Unslop-v2.1", - name: "Llama 3.3 70B Omega Directive Unslop v2.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "qwen3-30b-a3b-instruct-2507": { - id: "qwen3-30b-a3b-instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-20", - last_updated: "2025-02-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "gemini-2.5-flash-preview-09-2025-thinking": { - id: "gemini-2.5-flash-preview-09-2025-thinking", - name: "Gemini 2.5 Flash Preview (09/2025) – Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - deepclaude: { - id: "deepclaude", - name: "DeepClaude", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-01", - last_updated: "2025-02-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "ernie-4.5-8k-preview": { - id: "ernie-4.5-8k-preview", - name: "Ernie 4.5 8k Preview", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.66, output: 2.6 }, - limit: { context: 8000, input: 8000, output: 16384 }, - }, - "doubao-seed-2-0-mini-260215": { - id: "doubao-seed-2-0-mini-260215", - name: "Doubao Seed 2.0 Mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0493, output: 0.4845 }, - limit: { context: 256000, input: 256000, output: 32000 }, - }, - "gemini-3-pro-preview-thinking": { - id: "gemini-3-pro-preview-thinking", - name: "Gemini 3 Pro Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "Llama-3.3-70B-GeneticLemonade-Opus": { - id: "Llama-3.3-70B-GeneticLemonade-Opus", - name: "Llama 3.3 70B GeneticLemonade Opus", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "v0-1.5-lg": { - id: "v0-1.5-lg", - name: "v0 1.5 LG", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-04", - last_updated: "2025-07-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "ernie-4.5-turbo-128k": { - id: "ernie-4.5-turbo-128k", - name: "Ernie 4.5 Turbo 128k", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.132, output: 0.55 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "KAT-Coder-Pro-V1": { - id: "KAT-Coder-Pro-V1", - name: "KAT Coder Pro V1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-10-28", - last_updated: "2025-10-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 6 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "claude-3-5-sonnet-20240620": { - id: "claude-3-5-sonnet-20240620", - name: "Claude 3.5 Sonnet Old", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-06-20", - last_updated: "2024-06-20", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 8192 }, - }, - "claude-opus-4-1-thinking:8192": { - id: "claude-opus-4-1-thinking:8192", - name: "Claude 4.1 Opus Thinking (8K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "gemini-2.0-flash-exp-image-generation": { - id: "gemini-2.0-flash-exp-image-generation", - name: "Gemini Text + Image", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 32767, input: 32767, output: 8192 }, - }, - "Llama-3.3-70B-Magnum-v4-SE": { - id: "Llama-3.3-70B-Magnum-v4-SE", - name: "Llama 3.3 70B Magnum v4 SE", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "glm-zero-preview": { - id: "glm-zero-preview", - name: "GLM Zero Preview", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.802, output: 1.802 }, - limit: { context: 8000, input: 8000, output: 4096 }, - }, - "study_gpt-chatgpt-4o-latest": { - id: "study_gpt-chatgpt-4o-latest", - name: "Study Mode", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 16384 }, - }, - "glm-4-airx": { - id: "glm-4-airx", - name: "GLM-4 AirX", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-05", - last_updated: "2024-06-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.006 }, - limit: { context: 8000, input: 8000, output: 4096 }, - }, - "step-2-mini": { - id: "step-2-mini", - name: "Step-2 Mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-05", - last_updated: "2024-07-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.408 }, - limit: { context: 8000, input: 8000, output: 4096 }, - }, - "gemini-2.5-flash-preview-04-17:thinking": { - id: "gemini-2.5-flash-preview-04-17:thinking", - name: "Gemini 2.5 Flash Preview Thinking", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-04-17", - last_updated: "2025-04-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 3.5 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "Llama-3.3-70B-Mokume-Gane-R1": { - id: "Llama-3.3-70B-Mokume-Gane-R1", - name: "Llama 3.3 70B Mokume Gane R1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "deepseek-reasoner": { - id: "deepseek-reasoner", - name: "DeepSeek Reasoner", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.7 }, - limit: { context: 64000, input: 64000, output: 65536 }, - }, - "glm-z1-airx": { - id: "glm-z1-airx", - name: "GLM Z1 AirX", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "jamba-mini-1.6": { - id: "jamba-mini-1.6", - name: "Jamba Mini 1.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1989, output: 0.408 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "claude-opus-4-1-thinking": { - id: "claude-opus-4-1-thinking", - name: "Claude 4.1 Opus Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "grok-3-beta": { - id: "grok-3-beta", - name: "Grok 3 Beta", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 131072, input: 131072, output: 131072 }, - }, - "Llama-3.3-70B-Legion-V2.1": { - id: "Llama-3.3-70B-Legion-V2.1", - name: "Llama 3.3 70B Legion V2.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - sonar: { - id: "sonar", - name: "Perplexity Simple", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.003, output: 1.003 }, - limit: { context: 127000, input: 127000, output: 128000 }, - }, - "z-image-turbo": { - id: "z-image-turbo", - name: "Z Image Turbo", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-11-27", - last_updated: "2025-11-27", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "GLM-4.5-Air-Derestricted-Iceblink-v2": { - id: "GLM-4.5-Air-Derestricted-Iceblink-v2", - name: "GLM 4.5 Air Derestricted Iceblink v2", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 158600, input: 158600, output: 65536 }, - }, - "jamba-large": { - id: "jamba-large", - name: "Jamba Large", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.989, output: 7.99 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "claude-3-7-sonnet-reasoner": { - id: "claude-3-7-sonnet-reasoner", - name: "Claude 3.7 Sonnet Reasoner", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-29", - last_updated: "2025-03-29", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "ernie-4.5-turbo-vl-32k": { - id: "ernie-4.5-turbo-vl-32k", - name: "Ernie 4.5 Turbo VL 32k", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.495, output: 1.43 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "Mistral-Nemo-12B-Instruct-2407": { - id: "Mistral-Nemo-12B-Instruct-2407", - name: "Mistral Nemo 12B Instruct 2407", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.01, output: 0.01 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "doubao-seed-1-6-flash-250615": { - id: "doubao-seed-1-6-flash-250615", - name: "Doubao Seed 1.6 Flash", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-15", - last_updated: "2025-06-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0374, output: 0.374 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "qwq-32b": { - id: "qwq-32b", - name: "Qwen: QwQ 32B", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25599999, output: 0.30499999 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "Llama-3.3-70B-Strawberrylemonade-v1.2": { - id: "Llama-3.3-70B-Strawberrylemonade-v1.2", - name: "Llama 3.3 70B StrawberryLemonade v1.2", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "gemini-2.5-flash-preview-04-17": { - id: "gemini-2.5-flash-preview-04-17", - name: "Gemini 2.5 Flash Preview", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-04-17", - last_updated: "2025-04-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "ernie-x1-turbo-32k": { - id: "ernie-x1-turbo-32k", - name: "Ernie X1 Turbo 32k", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.165, output: 0.66 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "deepseek-math-v2": { - id: "deepseek-math-v2", - name: "DeepSeek Math V2", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "Llama-3.3-70B-Electranova-v1.0": { - id: "Llama-3.3-70B-Electranova-v1.0", - name: "Llama 3.3 70B Electranova v1.0", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-ArliAI-RPMax-v2": { - id: "Llama-3.3-70B-ArliAI-RPMax-v2", - name: "Llama 3.3 70B ArliAI RPMax v2", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "qwen-image": { - id: "qwen-image", - name: "Qwen Image", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "Llama-3.3-70B-Cu-Mai-R1": { - id: "Llama-3.3-70B-Cu-Mai-R1", - name: "Llama 3.3 70B Cu Mai R1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "GLM-4.5-Air-Derestricted-Iceblink": { - id: "GLM-4.5-Air-Derestricted-Iceblink", - name: "GLM 4.5 Air Derestricted Iceblink", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 131072, input: 131072, output: 98304 }, - }, - "Llama-3.3-70B-Bigger-Body": { - id: "Llama-3.3-70B-Bigger-Body", - name: "Llama 3.3 70B Bigger Body", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - 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", - name: "Llama 3.3+ 70B Hanami x1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "hunyuan-turbos-20250226": { - id: "hunyuan-turbos-20250226", - name: "Hunyuan Turbo S", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.187, output: 0.374 }, - limit: { context: 24000, input: 24000, output: 8192 }, - }, - "gemini-2.5-flash-preview-09-2025": { - id: "gemini-2.5-flash-preview-09-2025", - name: "Gemini 2.5 Flash Preview (09/2025)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "GLM-4.6-Derestricted-v5": { - id: "GLM-4.6-Derestricted-v5", - name: "GLM 4.6 Derestricted v5", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.5 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "glm-4-plus": { - id: "glm-4-plus", - name: "GLM-4 Plus", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-08-01", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 7.497, output: 7.497 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "Gemma-3-27B-Big-Tiger-v3": { - id: "Gemma-3-27B-Big-Tiger-v3", - name: "Gemma 3 27B Big Tiger v3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "brave-research": { - id: "brave-research", - name: "Brave (Research)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-03-02", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 5 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - hidream: { - id: "hidream", - name: "Hidream", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-01-01", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "qwen3-max-2026-01-23": { - id: "qwen3-max-2026-01-23", - name: "Qwen3 Max 2026-01-23", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-26", - last_updated: "2026-01-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2002, output: 6.001 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "Claude 4.1 Opus", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Claude Haiku 4.5", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "MiniMax-M1": { - id: "MiniMax-M1", - name: "MiniMax M1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-16", - last_updated: "2025-06-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1394, output: 1.3328 }, - limit: { context: 1000000, input: 1000000, output: 131072 }, - }, - "gemini-2.5-flash-nothinking": { - id: "gemini-2.5-flash-nothinking", - name: "Gemini 2.5 Flash (No Thinking)", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "exa-research-pro": { - id: "exa-research-pro", - name: "Exa (Research Pro)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-04", - last_updated: "2025-06-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 2.5 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "grok-3-fast-beta": { - id: "grok-3-fast-beta", - name: "Grok 3 Fast Beta", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 131072, input: 131072, output: 131072 }, - }, - "claude-opus-4-5-20251101:thinking": { - id: "claude-opus-4-5-20251101:thinking", - name: "Claude 4.5 Opus Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "gemini-2.5-pro-exp-03-25": { - id: "gemini-2.5-pro-exp-03-25", - name: "Gemini 2.5 Pro Experimental 0325", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "claude-3-7-sonnet-thinking": { - id: "claude-3-7-sonnet-thinking", - name: "Claude 3.7 Sonnet Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 16000 }, - }, - "claude-opus-4-thinking:8192": { - id: "claude-opus-4-thinking:8192", - name: "Claude 4 Opus Thinking (8K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "claude-sonnet-4-thinking:1024": { - id: "claude-sonnet-4-thinking:1024", - name: "Claude 4 Sonnet Thinking (1K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - 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", - name: "Llama 3.3 70B Magnum v4 SE Cirrus x1 SLERP", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "step-r1-v-mini": { - id: "step-r1-v-mini", - name: "Step R1 V Mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-08", - last_updated: "2025-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 11 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "ernie-x1-32k-preview": { - id: "ernie-x1-32k-preview", - name: "Ernie X1 32k", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 1.32 }, - limit: { context: 32000, input: 32000, output: 16384 }, - }, - "Llama-3.3-70B-StrawberryLemonade-v1.0": { - id: "Llama-3.3-70B-StrawberryLemonade-v1.0", - name: "Llama 3.3 70B StrawberryLemonade v1.0", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "KAT-Coder-Exp-72B-1010": { - id: "KAT-Coder-Exp-72B-1010", - name: "KAT Coder Exp 72B 1010", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-10-28", - last_updated: "2025-10-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.2 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "gemini-2.5-pro-preview-03-25": { - id: "gemini-2.5-pro-preview-03-25", - name: "Gemini 2.5 Pro Preview 0325", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "claude-opus-4-thinking:1024": { - id: "claude-opus-4-thinking:1024", - name: "Claude 4 Opus Thinking (1K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "Claude 4 Sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "Llama-3.3-70B-Progenitor-V3.3": { - id: "Llama-3.3-70B-Progenitor-V3.3", - name: "Llama 3.3 70B Progenitor V3.3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Qwen2.5-32B-EVA-v0.2": { - id: "Qwen2.5-32B-EVA-v0.2", - name: "Qwen 2.5 32b EVA", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-09-01", - last_updated: "2024-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.493, output: 0.493 }, - limit: { context: 24576, input: 24576, output: 8192 }, - }, - "brave-pro": { - id: "brave-pro", - name: "Brave (Pro)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-03-02", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 5 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "step-2-16k-exp": { - id: "step-2-16k-exp", - name: "Step-2 16k Exp", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-05", - last_updated: "2024-07-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 7.004, output: 19.992 }, - limit: { context: 16000, input: 16000, output: 8192 }, - }, - "Llama-3.3-70B-Fallen-R1-v1": { - id: "Llama-3.3-70B-Fallen-R1-v1", - name: "Llama 3.3 70B Fallen R1 v1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "claude-sonnet-4-thinking": { - id: "claude-sonnet-4-thinking", - name: "Claude 4 Sonnet Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "doubao-1.5-pro-256k": { - id: "doubao-1.5-pro-256k", - name: "Doubao 1.5 Pro 256k", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.799, output: 1.445 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "claude-3-7-sonnet-20250219": { - id: "claude-3-7-sonnet-20250219", - name: "Claude 3.7 Sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 200000, input: 200000, output: 16000 }, - }, - "learnlm-1.5-pro-experimental": { - id: "learnlm-1.5-pro-experimental", - name: "Gemini LearnLM Experimental", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-14", - last_updated: "2024-05-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3.502, output: 10.506 }, - limit: { context: 32767, input: 32767, output: 8192 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3 Coder 30B A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - chroma: { - id: "chroma", - name: "Chroma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "Llama-3.3-70B-Predatorial-Extasy": { - id: "Llama-3.3-70B-Predatorial-Extasy", - name: "Llama 3.3 70B Predatorial Extasy", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-Aurora-Borealis": { - id: "Llama-3.3-70B-Aurora-Borealis", - name: "Llama 3.3 70B Aurora Borealis", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-ArliAI-RPMax-v3": { - id: "Llama-3.3-70B-ArliAI-RPMax-v3", - name: "Llama 3.3 70B ArliAI RPMax v3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "venice-uncensored": { - id: "venice-uncensored", - name: "Venice Uncensored", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "step-3": { - id: "step-3", - name: "Step-3", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2499, output: 0.6494 }, - 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", - name: "Llama 3.3 70B Omega Directive Unslop v2.0", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "auto-model": { - id: "auto-model", - name: "Auto model", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1000000, input: 1000000, output: 1000000 }, - }, - "claude-opus-4-1-thinking:32768": { - id: "claude-opus-4-1-thinking:32768", - name: "Claude 4.1 Opus Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "Llama-3.3-70B-Shakudo": { - id: "Llama-3.3-70B-Shakudo", - name: "Llama 3.3 70B Shakudo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Baichuan4-Air": { - id: "Baichuan4-Air", - name: "Baichuan 4 Air", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.157, output: 0.157 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "kimi-thinking-preview": { - id: "kimi-thinking-preview", - name: "Kimi Thinking Preview", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 31.46, output: 31.46 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "qwen-turbo": { - id: "qwen-turbo", - name: "Qwen Turbo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04998, output: 0.2006 }, - limit: { context: 1000000, input: 1000000, output: 8192 }, - }, - "Llama-3.3-70B-Mhnnn-x1": { - id: "Llama-3.3-70B-Mhnnn-x1", - name: "Llama 3.3 70B Mhnnn x1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "claude-opus-4-thinking:32768": { - id: "claude-opus-4-thinking:32768", - name: "Claude 4 Opus Thinking (32K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "Llama-3.3-70B-Argunaut-1-SFT": { - id: "Llama-3.3-70B-Argunaut-1-SFT", - name: "Llama 3.3 70B Argunaut 1 SFT", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "claude-opus-4-1-thinking:1024": { - id: "claude-opus-4-1-thinking:1024", - name: "Claude 4.1 Opus Thinking (1K)", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "phi-4-multimodal-instruct": { - id: "phi-4-multimodal-instruct", - name: "Phi 4 Multimodal", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.11 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "doubao-seed-2-0-code-preview-260215": { - id: "doubao-seed-2-0-code-preview-260215", - name: "Doubao Seed 2.0 Code Preview", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.782, output: 3.893 }, - limit: { context: 256000, input: 256000, output: 128000 }, - }, - "deepseek-reasoner-cheaper": { - id: "deepseek-reasoner-cheaper", - name: "Deepseek R1 Cheaper", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.7 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "exa-answer": { - id: "exa-answer", - name: "Exa (Answer)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-04", - last_updated: "2025-06-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 2.5 }, - limit: { context: 4096, input: 4096, output: 4096 }, - }, - "v0-1.0-md": { - id: "v0-1.0-md", - name: "v0 1.0 MD", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-04", - last_updated: "2025-07-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "glm-4.1v-thinking-flash": { - id: "glm-4.1v-thinking-flash", - name: "GLM 4.1V Thinking Flash", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 64000, input: 64000, output: 8192 }, - }, - "azure-o1": { - id: "azure-o1", - name: "Azure o1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-17", - last_updated: "2024-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 59.993 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "GLM-4.5-Air-Derestricted": { - id: "GLM-4.5-Air-Derestricted", - name: "GLM 4.5 Air Derestricted", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 202600, input: 202600, output: 98304 }, - }, - "azure-o3-mini": { - id: "azure-o3-mini", - name: "Azure o3-mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.088, output: 4.3996 }, - limit: { context: 200000, input: 200000, output: 65536 }, - }, - "qwen3.6-max-preview": { - id: "qwen3.6-max-preview", - name: "Qwen3.6 Max Preview", - family: "qwen3.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-04-20", - last_updated: "2026-04-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.3, output: 7.8 }, - limit: { context: 245800, output: 65536 }, - }, - "Llama-3.3-70B-Sapphira-0.2": { - id: "Llama-3.3-70B-Sapphira-0.2", - name: "Llama 3.3 70B Sapphira 0.2", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-Anthrobomination": { - id: "Llama-3.3-70B-Anthrobomination", - name: "Llama 3.3 70B Anthrobomination", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "QwQ-32B-ArliAI-RpR-v1": { - id: "QwQ-32B-ArliAI-RpR-v1", - name: "QwQ 32b Arli V1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "Claude 4 Opus", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-05-14", - last_updated: "2025-05-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 14.994, output: 75.004 }, - limit: { context: 200000, input: 200000, output: 32000 }, - }, - "yi-lightning": { - id: "yi-lightning", - name: "Yi Lightning", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-10-16", - last_updated: "2024-10-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 12000, input: 12000, output: 4096 }, - }, - "Llama-3.3-70B-Electra-R1": { - id: "Llama-3.3-70B-Electra-R1", - name: "Llama 3.3 70B Electra R1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-Forgotten-Abomination-v5.0": { - id: "Llama-3.3-70B-Forgotten-Abomination-v5.0", - name: "Llama 3.3 70B Forgotten Abomination v5.0", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Llama-3.3-70B-Cirrus-x1": { - id: "Llama-3.3-70B-Cirrus-x1", - name: "Llama 3.3 70B Cirrus x1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "grok-3-mini-beta": { - id: "grok-3-mini-beta", - name: "Grok 3 Mini Beta", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5 }, - limit: { context: 131072, input: 131072, output: 131072 }, - }, - "auto-model-standard": { - id: "auto-model-standard", - name: "Auto model (Standard)", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 1000000, input: 1000000, output: 1000000 }, - }, - "claude-sonnet-4-5-20250929-thinking": { - id: "claude-sonnet-4-5-20250929-thinking", - name: "Claude Sonnet 4.5 Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.994 }, - limit: { context: 1000000, input: 1000000, output: 64000 }, - }, - "v0-1.5-md": { - id: "v0-1.5-md", - name: "v0 1.5 MD", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-04", - last_updated: "2025-07-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, input: 200000, output: 64000 }, - }, - "kimi-k2-instruct-fast": { - id: "kimi-k2-instruct-fast", - name: "Kimi K2 0711 Fast", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-15", - last_updated: "2025-07-15", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 2 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "glm-4-long": { - id: "glm-4-long", - name: "GLM-4 Long", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-08-01", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 1000000, input: 1000000, output: 4096 }, - }, - "jamba-large-1.7": { - id: "jamba-large-1.7", - name: "Jamba Large 1.7", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.989, output: 7.99 }, - limit: { context: 256000, input: 256000, output: 4096 }, - }, - "qvq-max": { - id: "qvq-max", - name: "Qwen: QvQ Max", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-28", - last_updated: "2025-03-28", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 5.3 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "gemini-2.0-flash-thinking-exp-1219": { - id: "gemini-2.0-flash-thinking-exp-1219", - name: "Gemini 2.0 Flash Thinking 1219", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-19", - last_updated: "2024-12-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.408 }, - limit: { context: 32767, input: 32767, output: 8192 }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0748, output: 0.306 }, - limit: { context: 1000000, input: 1000000, output: 8192 }, - }, - "azure-gpt-4-turbo": { - id: "azure-gpt-4-turbo", - name: "Azure gpt-4-turbo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-11-06", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 30.005 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "Baichuan-M2": { - id: "Baichuan-M2", - name: "Baichuan M2 32B Medical", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 15.73, output: 15.73 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "qwen-long": { - id: "qwen-long", - name: "Qwen Long 10M", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.408 }, - limit: { context: 10000000, input: 10000000, output: 8192 }, - }, - "sonar-reasoning-pro": { - id: "sonar-reasoning-pro", - name: "Perplexity Reasoning Pro", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 7.9985 }, - limit: { context: 127000, input: 127000, output: 128000 }, - }, - "gemini-2.5-flash-preview-05-20:thinking": { - id: "gemini-2.5-flash-preview-05-20:thinking", - name: "Gemini 2.5 Flash 0520 Thinking", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 3.5 }, - limit: { context: 1048000, input: 1048000, output: 65536 }, - }, - "GLM-4.5-Air-Derestricted-Steam-ReExtract": { - id: "GLM-4.5-Air-Derestricted-Steam-ReExtract", - name: "GLM 4.5 Air Derestricted Steam ReExtract", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-12", - last_updated: "2025-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 131072, input: 131072, output: 65536 }, - }, - "Llama-3.3-70B-Dark-Ages-v0.1": { - id: "Llama-3.3-70B-Dark-Ages-v0.1", - name: "Llama 3.3 70B Dark Ages v0.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "Baichuan4-Turbo": { - id: "Baichuan4-Turbo", - name: "Baichuan 4 Turbo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.42, output: 2.42 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "doubao-1.5-vision-pro-32k": { - id: "doubao-1.5-vision-pro-32k", - name: "Doubao 1.5 Vision Pro 32k", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-22", - last_updated: "2025-01-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.459, output: 1.377 }, - limit: { context: 32000, input: 32000, output: 8192 }, - }, - "alibaba/qwen3.6-flash": { - id: "alibaba/qwen3.6-flash", - name: "Qwen3.6 Flash", - family: "qwen3.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19, output: 1.16 }, - limit: { context: 991800, output: 65536 }, - }, - "inflection/inflection-3-pi": { - id: "inflection/inflection-3-pi", - name: "Inflection 3 Pi", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-10-11", - last_updated: "2024-10-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 9.996 }, - limit: { context: 8000, input: 8000, output: 4096 }, - }, - "inflection/inflection-3-productivity": { - id: "inflection/inflection-3-productivity", - name: "Inflection 3 Productivity", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-10-11", - last_updated: "2024-10-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 9.996 }, - limit: { context: 8000, input: 8000, output: 4096 }, - }, - "essentialai/rnj-1-instruct": { - id: "essentialai/rnj-1-instruct", - name: "RNJ-1 Instruct 8B", - family: "rnj", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-13", - last_updated: "2025-12-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "LLM360/K2-Think": { - id: "LLM360/K2-Think", - name: "K2-Think", - family: "kimi-thinking", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "TEE/kimi-k2.5": { - id: "TEE/kimi-k2.5", - name: "Kimi K2.5 TEE", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.9 }, - limit: { context: 128000, input: 128000, output: 65535 }, - }, - "TEE/glm-4.7": { - id: "TEE/glm-4.7", - name: "GLM 4.7 TEE", - family: "glm", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.85, output: 3.3 }, - limit: { context: 131000, input: 131000, output: 65535 }, - }, - "TEE/qwen3.5-397b-a17b": { - id: "TEE/qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-28", - last_updated: "2026-02-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 258048, input: 258048, output: 65536 }, - }, - "TEE/glm-5": { - id: "TEE/glm-5", - name: "GLM 5 TEE", - family: "glm", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 3.5 }, - limit: { context: 203000, input: 203000, output: 65535 }, - }, - "TEE/qwen2.5-vl-72b-instruct": { - id: "TEE/qwen2.5-vl-72b-instruct", - name: "Qwen2.5 VL 72B TEE", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-01", - last_updated: "2025-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "TEE/minimax-m2.1": { - id: "TEE/minimax-m2.1", - name: "MiniMax M2.1 TEE", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 200000, input: 200000, output: 131072 }, - }, - "TEE/qwen3-30b-a3b-instruct-2507": { - id: "TEE/qwen3-30b-a3b-instruct-2507", - name: "Qwen3 30B A3B Instruct 2507 TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.44999999999999996 }, - limit: { context: 262000, input: 262000, output: 32768 }, - }, - "TEE/deepseek-v3.1": { - id: "TEE/deepseek-v3.1", - name: "DeepSeek V3.1 TEE", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2.5 }, - limit: { context: 164000, input: 164000, output: 8192 }, - }, - "TEE/llama3-3-70b": { - id: "TEE/llama3-3-70b", - name: "Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-03", - last_updated: "2025-07-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 2 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "TEE/glm-4.6": { - id: "TEE/glm-4.6", - name: "GLM 4.6 TEE", - family: "glm", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 2 }, - limit: { context: 203000, input: 203000, output: 65535 }, - }, - "TEE/kimi-k2.5-thinking": { - id: "TEE/kimi-k2.5-thinking", - name: "Kimi K2.5 Thinking TEE", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.9 }, - limit: { context: 128000, input: 128000, output: 65535 }, - }, - "TEE/gemma-3-27b-it": { - id: "TEE/gemma-3-27b-it", - name: "Gemma 3 27B TEE", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "TEE/deepseek-v3.2": { - id: "TEE/deepseek-v3.2", - name: "DeepSeek V3.2 TEE", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1 }, - limit: { context: 164000, input: 164000, output: 65536 }, - }, - "TEE/gpt-oss-20b": { - id: "TEE/gpt-oss-20b", - name: "GPT-OSS 20B TEE", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "TEE/qwen3-coder": { - id: "TEE/qwen3-coder", - name: "Qwen3 Coder 480B TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "TEE/glm-4.7-flash": { - id: "TEE/glm-4.7-flash", - name: "GLM 4.7 Flash TEE", - family: "glm-flash", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.5 }, - limit: { context: 203000, input: 203000, output: 65535 }, - }, - "TEE/gpt-oss-120b": { - id: "TEE/gpt-oss-120b", - name: "GPT-OSS 120B TEE", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 2 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "TEE/deepseek-r1-0528": { - id: "TEE/deepseek-r1-0528", - name: "DeepSeek R1 0528 TEE", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 2 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "TEE/kimi-k2-thinking": { - id: "TEE/kimi-k2-thinking", - name: "Kimi K2 Thinking TEE", - family: "kimi-thinking", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 2 }, - limit: { context: 128000, input: 128000, output: 65535 }, - }, - "CrucibleLab/L3.3-70B-Loki-V2.0": { - id: "CrucibleLab/L3.3-70B-Loki-V2.0", - name: "L3.3 70B Loki v2.0", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "deepseek/deepseek-v3.2:thinking": { - id: "deepseek/deepseek-v3.2:thinking", - name: "DeepSeek V3.2 Thinking", - family: "deepseek", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 163000, input: 163000, output: 65536 }, - }, - "deepseek/deepseek-prover-v2-671b": { - id: "deepseek/deepseek-prover-v2-671b", - name: "DeepSeek Prover v2 671B", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-30", - last_updated: "2025-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2.5 }, - limit: { context: 160000, input: 160000, output: 16384 }, - }, - "deepseek/deepseek-v3.2-speciale": { - id: "deepseek/deepseek-v3.2-speciale", - name: "DeepSeek V3.2 Speciale", - family: "deepseek", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 163000, input: 163000, output: 65536 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 163000, input: 163000, output: 65536 }, - }, - "Doctor-Shotgun/MS3.2-24B-Magnum-Diamond": { - id: "Doctor-Shotgun/MS3.2-24B-Magnum-Diamond", - name: "MS3.2 24B Magnum Diamond", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "NeverSleep/Llama-3-Lumimaid-70B-v0.1": { - id: "NeverSleep/Llama-3-Lumimaid-70B-v0.1", - name: "Lumimaid 70b", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.006 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "NeverSleep/Lumimaid-v0.2-70B": { - id: "NeverSleep/Lumimaid-v0.2-70B", - name: "Lumimaid v0.2", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1.5 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "Steelskull/L3.3-Cu-Mai-R1-70b": { - id: "Steelskull/L3.3-Cu-Mai-R1-70b", - name: "Llama 3.3 70B Cu Mai", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Steelskull/L3.3-Nevoria-R1-70b": { - id: "Steelskull/L3.3-Nevoria-R1-70b", - name: "Steelskull Nevoria R1 70b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Steelskull/L3.3-MS-Evayale-70B": { - id: "Steelskull/L3.3-MS-Evayale-70B", - name: "Evayale 70b ", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Steelskull/L3.3-Electra-R1-70b": { - id: "Steelskull/L3.3-Electra-R1-70b", - name: "Steelskull Electra R1 70b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.69989, output: 0.69989 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Steelskull/L3.3-MS-Nevoria-70b": { - id: "Steelskull/L3.3-MS-Nevoria-70b", - name: "Steelskull Nevoria 70b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Steelskull/L3.3-MS-Evalebis-70b": { - id: "Steelskull/L3.3-MS-Evalebis-70b", - name: "MS Evalebis 70b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "miromind-ai/mirothinker-v1.5-235b": { - id: "miromind-ai/mirothinker-v1.5-235b", - name: "MiroThinker v1.5 235B", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-07", - last_updated: "2026-01-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 32768, input: 32768, output: 4000 }, - }, - "pamanseau/OpenReasoning-Nemotron-32B": { - id: "pamanseau/OpenReasoning-Nemotron-32B", - name: "OpenReasoning Nemotron 32B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 32768, input: 32768, output: 65536 }, - }, - "arcee-ai/trinity-mini": { - id: "arcee-ai/trinity-mini", - name: "Trinity Mini", - family: "trinity-mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.045000000000000005, output: 0.15 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "arcee-ai/trinity-large": { - id: "arcee-ai/trinity-large", - name: "Trinity Large", - family: "trinity", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "cognitivecomputations/dolphin-2.9.2-qwen2-72b": { - id: "cognitivecomputations/dolphin-2.9.2-qwen2-72b", - name: "Dolphin 72b", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.306 }, - limit: { context: 8192, input: 8192, output: 4096 }, - }, - "deepcogito/cogito-v1-preview-qwen-32B": { - id: "deepcogito/cogito-v1-preview-qwen-32B", - name: "Cogito v1 Preview Qwen 32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-10", - last_updated: "2025-05-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.7999999999999998, output: 1.7999999999999998 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "deepcogito/cogito-v2.1-671b": { - id: "deepcogito/cogito-v2.1-671b", - name: "Cogito v2.1 671B MoE", - family: "cogito", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 1.25 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "Salesforce/Llama-xLAM-2-70b-fc-r": { - id: "Salesforce/Llama-xLAM-2-70b-fc-r", - name: "Llama-xLAM-2 70B fc-r", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-13", - last_updated: "2025-04-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 2.5 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "NousResearch 2/hermes-4-405b:thinking": { - id: "NousResearch 2/hermes-4-405b:thinking", - name: "Hermes 4 Large (Thinking)", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "NousResearch 2/DeepHermes-3-Mistral-24B-Preview": { - id: "NousResearch 2/DeepHermes-3-Mistral-24B-Preview", - name: "DeepHermes-3 Mistral 24B (Preview)", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-10", - last_updated: "2025-05-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "NousResearch 2/Hermes-4-70B:thinking": { - id: "NousResearch 2/Hermes-4-70B:thinking", - name: "Hermes 4 (Thinking)", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-17", - last_updated: "2025-09-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.39949999999999997 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "NousResearch 2/hermes-4-405b": { - id: "NousResearch 2/hermes-4-405b", - name: "Hermes 4 Large", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "NousResearch 2/hermes-3-llama-3.1-70b": { - id: "NousResearch 2/hermes-3-llama-3.1-70b", - name: "Hermes 3 70B", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-07", - last_updated: "2026-01-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.408, output: 0.408 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "NousResearch 2/hermes-4-70b": { - id: "NousResearch 2/hermes-4-70b", - name: "Hermes 4 Medium", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-03", - last_updated: "2025-07-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.39949999999999997 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "soob3123/Veiled-Calla-12B": { - id: "soob3123/Veiled-Calla-12B", - name: "Veiled Calla 12B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-13", - last_updated: "2025-04-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "soob3123/GrayLine-Qwen3-8B": { - id: "soob3123/GrayLine-Qwen3-8B", - name: "Grayline Qwen3 8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "soob3123/amoral-gemma3-27B-v2": { - id: "soob3123/amoral-gemma3-27B-v2", - name: "Amoral Gemma3 27B v2", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-05-23", - last_updated: "2025-05-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "nex-agi/deepseek-v3.1-nex-n1": { - id: "nex-agi/deepseek-v3.1-nex-n1", - name: "DeepSeek V3.1 Nex N1", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-10", - last_updated: "2025-12-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "Envoid/Llama-3.05-NT-Storybreaker-Ministral-70B": { - id: "Envoid/Llama-3.05-NT-Storybreaker-Ministral-70B", - name: "Llama 3.05 Storybreaker Ministral 70b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "Envoid/Llama-3.05-Nemotron-Tenyxchat-Storybreaker-70B": { - id: "Envoid/Llama-3.05-Nemotron-Tenyxchat-Storybreaker-70B", - name: "Nemotron Tenyxchat Storybreaker 70b", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "anthracite-org/magnum-v4-72b": { - id: "anthracite-org/magnum-v4-72b", - name: "Magnum v4 72B", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.992 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "anthracite-org/magnum-v2-72b": { - id: "anthracite-org/magnum-v2-72b", - name: "Magnum V2 72B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.992 }, - 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", - name: "Omega Directive 24B Unslop v2.0", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 0.5 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "ReadyArt/The-Omega-Abomination-L-70B-v1.0": { - id: "ReadyArt/The-Omega-Abomination-L-70B-v1.0", - name: "The Omega Abomination V1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.95 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "undi95/remm-slerp-l2-13b": { - id: "undi95/remm-slerp-l2-13b", - name: "ReMM SLERP 13B", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7989999999999999, output: 1.2069999999999999 }, - limit: { context: 6144, input: 6144, output: 4096 }, - }, - "MarinaraSpaghetti/NemoMix-Unleashed-12B": { - id: "MarinaraSpaghetti/NemoMix-Unleashed-12B", - name: "NemoMix 12B Unleashed", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "allenai/molmo-2-8b": { - id: "allenai/molmo-2-8b", - name: "Molmo 2 8B", - family: "allenai", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 36864, input: 36864, output: 36864 }, - }, - "allenai/olmo-3.1-32b-instruct": { - id: "allenai/olmo-3.1-32b-instruct", - name: "Olmo 3.1 32B Instruct", - family: "allenai", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-25", - last_updated: "2026-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "allenai/olmo-3.1-32b-think": { - id: "allenai/olmo-3.1-32b-think", - name: "Olmo 3.1 32B Think", - family: "allenai", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-01-25", - last_updated: "2026-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.5 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "allenai/olmo-3-32b-think": { - id: "allenai/olmo-3-32b-think", - name: "Olmo 3 32B Think", - family: "allenai", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.44999999999999996 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "stepfun-ai/step-3.5-flash:thinking": { - id: "stepfun-ai/step-3.5-flash:thinking", - name: "Step 3.5 Flash Thinking", - family: "step", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 256000, input: 256000, output: 256000 }, - }, - "stepfun-ai/step-3.5-flash": { - id: "stepfun-ai/step-3.5-flash", - name: "Step 3.5 Flash", - family: "step", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 256000, input: 256000, output: 256000 }, - }, - "zai-org/glm-4.7": { - id: "zai-org/glm-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.8 }, - limit: { context: 200000, input: 200000, output: 128000 }, - }, - "zai-org/glm-5": { - id: "zai-org/glm-5", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.55 }, - limit: { context: 200000, input: 200000, output: 128000 }, - }, - "zai-org/glm-5.1": { - id: "zai-org/glm-5.1", - name: "GLM 5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.55 }, - limit: { context: 200000, input: 200000, output: 131072 }, - }, - "zai-org/glm-5.1:thinking": { - id: "zai-org/glm-5.1:thinking", - name: "GLM 5.1 Thinking", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.55 }, - limit: { context: 200000, input: 200000, output: 131072 }, - }, - "zai-org/glm-5:thinking": { - id: "zai-org/glm-5:thinking", - name: "GLM 5 Thinking", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.55 }, - limit: { context: 200000, input: 200000, output: 128000 }, - }, - "zai-org/glm-4.7-flash": { - id: "zai-org/glm-4.7-flash", - name: "GLM 4.7 Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4 }, - limit: { context: 200000, input: 200000, output: 128000 }, - }, - "featherless-ai/Qwerky-72B": { - id: "featherless-ai/Qwerky-72B", - name: "Qwerky 72B", - family: "qwerky", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-20", - last_updated: "2025-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 0.5 }, - limit: { context: 32000, input: 32000, output: 8192 }, - }, - "mlabonne/NeuralDaredevil-8B-abliterated": { - id: "mlabonne/NeuralDaredevil-8B-abliterated", - name: "Neural Daredevil 8B abliterated", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.44, output: 0.44 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "raifle/sorcererlm-8x22b": { - id: "raifle/sorcererlm-8x22b", - name: "SorcererLM 8x22B", - family: "mixtral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.505, output: 4.505 }, - limit: { context: 16000, input: 16000, output: 8192 }, - }, - "mistralai/mixtral-8x7b-instruct-v0.1": { - id: "mistralai/mixtral-8x7b-instruct-v0.1", - name: "Mixtral 8x7B", - family: "mixtral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "mistralai/mistral-saba": { - id: "mistralai/mistral-saba", - name: "Mistral Saba", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1989, output: 0.595 }, - limit: { context: 32000, input: 32000, output: 32768 }, - }, - "mistralai/mistral-large-3-675b-instruct-2512": { - id: "mistralai/mistral-large-3-675b-instruct-2512", - name: "Mistral Large 3 675B", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3 }, - limit: { context: 262144, input: 262144, output: 256000 }, - }, - "mistralai/devstral-2-123b-instruct-2512": { - id: "mistralai/devstral-2-123b-instruct-2512", - name: "Devstral 2 123B", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.4 }, - limit: { context: 262144, input: 262144, output: 65536 }, - }, - "mistralai/codestral-2508": { - id: "mistralai/codestral-2508", - name: "Codestral 2508", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.8999999999999999 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "mistralai/ministral-14b-instruct-2512": { - id: "mistralai/ministral-14b-instruct-2512", - name: "Ministral 3 14B", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 262144, input: 262144, output: 32768 }, - }, - "mistralai/mistral-tiny": { - id: "mistralai/mistral-tiny", - name: "Mistral Tiny", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-12-11", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25499999999999995, output: 0.25499999999999995 }, - limit: { context: 32000, input: 32000, output: 8192 }, - }, - "mistralai/ministral-8b-2512": { - id: "mistralai/ministral-8b-2512", - name: "Ministral 8B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-04", - last_updated: "2025-12-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 262144, input: 262144, output: 32768 }, - }, - "mistralai/mixtral-8x22b-instruct-v0.1": { - id: "mistralai/mixtral-8x22b-instruct-v0.1", - name: "Mixtral 8x22B", - family: "mixtral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8999999999999999, output: 0.8999999999999999 }, - limit: { context: 65536, input: 65536, output: 32768 }, - }, - "mistralai/mistral-medium-3.1": { - id: "mistralai/mistral-medium-3.1", - name: "Mistral Medium 3.1", - family: "mistral-medium", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, input: 131072, output: 32768 }, - }, - "mistralai/ministral-3b-2512": { - id: "mistralai/ministral-3b-2512", - name: "Ministral 3B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-04", - last_updated: "2025-12-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, input: 131072, output: 32768 }, - }, - "mistralai/Mistral-Nemo-Instruct-2407": { - id: "mistralai/Mistral-Nemo-Instruct-2407", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1207 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "mistralai/mistral-medium-3": { - id: "mistralai/mistral-medium-3", - name: "Mistral Medium 3", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, input: 131072, output: 32768 }, - }, - "mistralai/mistral-7b-instruct": { - id: "mistralai/mistral-7b-instruct", - name: "Mistral 7B Instruct", - family: "mistral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-27", - last_updated: "2024-05-27", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0544, output: 0.0544 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "mistralai/Devstral-Small-2505": { - id: "mistralai/Devstral-Small-2505", - name: "Mistral Devstral Small 2505", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-02", - last_updated: "2025-08-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.060000000000000005, output: 0.060000000000000005 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "mistralai/mistral-small-creative": { - id: "mistralai/mistral-small-creative", - name: "Mistral Small Creative", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "mistralai/mistral-large": { - id: "mistralai/mistral-large", - name: "Mistral Large 2411", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-02-26", - last_updated: "2024-02-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 6.001 }, - limit: { context: 128000, input: 128000, output: 256000 }, - }, - "mistralai/ministral-14b-2512": { - id: "mistralai/ministral-14b-2512", - name: "Ministral 14B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-04", - last_updated: "2025-12-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 262144, input: 262144, output: 32768 }, - }, - "shisa-ai/shisa-v2.1-llama3.3-70b": { - id: "shisa-ai/shisa-v2.1-llama3.3-70b", - name: "Shisa V2.1 Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 0.5 }, - limit: { context: 32768, input: 32768, output: 4096 }, - }, - "shisa-ai/shisa-v2-llama3.3-70b": { - id: "shisa-ai/shisa-v2-llama3.3-70b", - name: "Shisa V2 Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 0.5 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "meta-llama/llama-3.3-70b-instruct": { - id: "meta-llama/llama-3.3-70b-instruct", - name: "Llama 3.3 70b Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.23 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "meta-llama/llama-4-scout": { - id: "meta-llama/llama-4-scout", - name: "Llama 4 Scout", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.085, output: 0.46 }, - limit: { context: 328000, input: 328000, output: 65536 }, - }, - "meta-llama/llama-4-maverick": { - id: "meta-llama/llama-4-maverick", - name: "Llama 4 Maverick", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18000000000000002, output: 0.8 }, - limit: { context: 1048576, input: 1048576, output: 65536 }, - }, - "meta-llama/llama-3.2-90b-vision-instruct": { - id: "meta-llama/llama-3.2-90b-vision-instruct", - name: "Llama 3.2 Medium", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9009999999999999, output: 0.9009999999999999 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "meta-llama/llama-3.2-3b-instruct": { - id: "meta-llama/llama-3.2-3b-instruct", - name: "Llama 3.2 3b Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0306, output: 0.0493 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "meta-llama/llama-3.1-8b-instruct": { - id: "meta-llama/llama-3.1-8b-instruct", - name: "Llama 3.1 8b Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0544, output: 0.0544 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "GalrionSoftworks/MN-LooseCannon-12B-v1": { - id: "GalrionSoftworks/MN-LooseCannon-12B-v1", - name: "MN-LooseCannon-12B-v1", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "baseten/Kimi-K2-Instruct-FP4": { - id: "baseten/Kimi-K2-Instruct-FP4", - name: "Kimi K2 0711 Instruct FP4", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 2 }, - limit: { context: 128000, input: 128000, output: 131072 }, - }, - "Gryphe/MythoMax-L2-13b": { - id: "Gryphe/MythoMax-L2-13b", - name: "MythoMax 13B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1003 }, - limit: { context: 4000, input: 4000, output: 4096 }, - }, - "x-ai/grok-4-fast:thinking": { - id: "x-ai/grok-4-fast:thinking", - name: "Grok 4 Fast Thinking", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, input: 2000000, output: 131072 }, - }, - "x-ai/grok-4-07-09": { - id: "x-ai/grok-4-07-09", - name: "Grok 4", - family: "grok", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 256000, input: 256000, output: 131072 }, - }, - "x-ai/grok-4-fast": { - id: "x-ai/grok-4-fast", - name: "Grok 4 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-20", - last_updated: "2025-09-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, input: 2000000, output: 131072 }, - }, - "x-ai/grok-code-fast-1": { - id: "x-ai/grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 256000, input: 256000, output: 131072 }, - }, - "x-ai/grok-4.1-fast": { - id: "x-ai/grok-4.1-fast", - name: "Grok 4.1 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, input: 2000000, output: 131072 }, - }, - "x-ai/grok-4.1-fast-reasoning": { - id: "x-ai/grok-4.1-fast-reasoning", - name: "Grok 4.1 Fast Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, input: 2000000, output: 131072 }, - }, - "tencent/Hunyuan-MT-7B": { - id: "tencent/Hunyuan-MT-7B", - name: "Hunyuan MT 7B", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 20 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "microsoft/wizardlm-2-8x22b": { - id: "microsoft/wizardlm-2-8x22b", - name: "WizardLM-2 8x22B", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "microsoft/MAI-DS-R1-FP8": { - id: "microsoft/MAI-DS-R1-FP8", - name: "Microsoft DeepSeek R1", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "cohere/command-r": { - id: "cohere/command-r", - name: "Cohere: Command R", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-03-11", - last_updated: "2024-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.476, output: 1.428 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "cohere/command-r-plus-08-2024": { - id: "cohere/command-r-plus-08-2024", - name: "Cohere: Command R+", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.856, output: 14.246 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "chutesai/Mistral-Small-3.2-24B-Instruct-2506": { - id: "chutesai/Mistral-Small-3.2-24B-Instruct-2506", - name: "Mistral Small 3.2 24b Instruct", - family: "chutesai", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.4 }, - limit: { context: 128000, input: 128000, output: 131072 }, - }, - "nvidia/Llama-3.1-Nemotron-Ultra-253B-v1": { - id: "nvidia/Llama-3.1-Nemotron-Ultra-253B-v1", - name: "Nvidia Nemotron Ultra 253B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-03", - last_updated: "2025-07-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 0.8 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "nvidia/nemotron-3-nano-30b-a3b": { - id: "nvidia/nemotron-3-nano-30b-a3b", - name: "Nvidia Nemotron 3 Nano 30B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-15", - last_updated: "2025-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 256000, input: 256000, output: 262144 }, - }, - "nvidia/nvidia-nemotron-nano-9b-v2": { - id: "nvidia/nvidia-nemotron-nano-9b-v2", - name: "Nvidia Nemotron Nano 9B v2", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-18", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF": { - id: "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF", - name: "Nvidia Nemotron 70b", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.357, output: 0.408 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "nvidia/Llama-3.3-Nemotron-Super-49B-v1": { - id: "nvidia/Llama-3.3-Nemotron-Super-49B-v1", - name: "Nvidia Nemotron Super 49B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "nvidia/Llama-3_3-Nemotron-Super-49B-v1_5": { - id: "nvidia/Llama-3_3-Nemotron-Super-49B-v1_5", - name: "Nvidia Nemotron Super 49B v1.5", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.25 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "TheDrummer 2/Anubis-70B-v1": { - id: "TheDrummer 2/Anubis-70B-v1", - name: "Anubis 70B v1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.31, output: 0.31 }, - limit: { context: 65536, input: 65536, output: 16384 }, - }, - "TheDrummer 2/Cydonia-24B-v4.3": { - id: "TheDrummer 2/Cydonia-24B-v4.3", - name: "The Drummer Cydonia 24B v4.3", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-25", - last_updated: "2025-12-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1207 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "TheDrummer 2/Magidonia-24B-v4.3": { - id: "TheDrummer 2/Magidonia-24B-v4.3", - name: "The Drummer Magidonia 24B v4.3", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-25", - last_updated: "2025-12-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1207 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "TheDrummer 2/Cydonia-24B-v4": { - id: "TheDrummer 2/Cydonia-24B-v4", - name: "The Drummer Cydonia 24B v4", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2414 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "TheDrummer 2/Anubis-70B-v1.1": { - id: "TheDrummer 2/Anubis-70B-v1.1", - name: "Anubis 70B v1.1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.31, output: 0.31 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "TheDrummer 2/Rocinante-12B-v1.1": { - id: "TheDrummer 2/Rocinante-12B-v1.1", - name: "Rocinante 12b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.408, output: 0.595 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "TheDrummer 2/Cydonia-24B-v4.1": { - id: "TheDrummer 2/Cydonia-24B-v4.1", - name: "The Drummer Cydonia 24B v4.1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1207 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "TheDrummer 2/UnslopNemo-12B-v4.1": { - id: "TheDrummer 2/UnslopNemo-12B-v4.1", - name: "UnslopNemo 12b v4", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "TheDrummer 2/Cydonia-24B-v2": { - id: "TheDrummer 2/Cydonia-24B-v2", - name: "The Drummer Cydonia 24B v2", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1207 }, - limit: { context: 16384, input: 16384, output: 32768 }, - }, - "TheDrummer 2/skyfall-36b-v2": { - id: "TheDrummer 2/skyfall-36b-v2", - name: "TheDrummer Skyfall 36B V2", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 64000, input: 64000, output: 32768 }, - }, - "deepseek-ai/DeepSeek-V3.1:thinking": { - id: "deepseek-ai/DeepSeek-V3.1:thinking", - name: "DeepSeek V3.1 Thinking", - family: "deepseek-thinking", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus:thinking": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus:thinking", - name: "DeepSeek V3.1 Terminus (Thinking)", - family: "deepseek-thinking", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "deepseek-ai/deepseek-v3.2-exp-thinking": { - id: "deepseek-ai/deepseek-v3.2-exp-thinking", - name: "DeepSeek V3.2 Exp Thinking", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 163840, input: 163840, output: 65536 }, - }, - "deepseek-ai/deepseek-v3.2-exp": { - id: "deepseek-ai/deepseek-v3.2-exp", - name: "DeepSeek V3.2 Exp", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27999999999999997, output: 0.42000000000000004 }, - limit: { context: 163840, input: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek R1 0528", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.7 }, - limit: { context: 128000, input: 128000, output: 163840 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-02", - last_updated: "2025-08-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "GPT 5.1 Codex Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 20 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-5.2-chat": { - id: "openai/gpt-5.2-chat", - name: "GPT 5.2 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-01-01", - last_updated: "2026-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 400000, output: 16384 }, - }, - "openai/gpt-4o-mini-search-preview": { - id: "openai/gpt-4o-mini-search-preview", - name: "GPT-4o mini Search Preview", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.088, output: 0.35 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/chatgpt-4o-latest": { - id: "openai/chatgpt-4o-latest", - name: "ChatGPT 4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 14.993999999999998 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT 5.2 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-01-01", - last_updated: "2026-01-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT 5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT 5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-4-turbo": { - id: "openai/gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-11-06", - last_updated: "2024-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT 5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-01-01", - last_updated: "2026-01-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/o3-mini-high": { - id: "openai/o3-mini-high", - name: "OpenAI o3-mini (High)", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.64, output: 2.588 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1496, output: 0.595 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/o4-mini-deep-research": { - id: "openai/o4-mini-deep-research", - name: "OpenAI o4-mini Deep Research", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-5.1-chat": { - id: "openai/gpt-5.1-chat", - name: "GPT 5.1 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "OpenAI o4-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT 5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT 5.1 Codex Mini", - family: "gpt-codex-mini", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/o1-preview": { - id: "openai/o1-preview", - name: "OpenAI o1-preview", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 14.993999999999998, output: 59.993 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "openai/gpt-4o-2024-08-06": { - id: "openai/gpt-4o-2024-08-06", - name: "GPT-4o (2024-08-06)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-08-06", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 9.996 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT 5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/o1": { - id: "openai/o1", - name: "OpenAI o1", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2024-12-17", - last_updated: "2024-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 14.993999999999998, output: 59.993 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-3.5-turbo": { - id: "openai/gpt-3.5-turbo", - name: "GPT-3.5 Turbo", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2022-11-30", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 16385, input: 16385, output: 4096 }, - }, - "openai/o3-deep-research": { - id: "openai/o3-deep-research", - name: "OpenAI o3 Deep Research", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "OpenAI o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-4-turbo-preview": { - id: "openai/gpt-4-turbo-preview", - name: "GPT-4 Turbo Preview", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2023-11-06", - last_updated: "2024-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 30.004999999999995 }, - limit: { context: 128000, input: 128000, output: 4096 }, - }, - "openai/o1-pro": { - id: "openai/o1-pro", - name: "OpenAI o1 Pro", - family: "o-pro", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 150, output: 600 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5 Codex", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "openai/gpt-5.1-chat-latest": { - id: "openai/gpt-5.1-chat-latest", - name: "GPT 5.1 Chat (Latest)", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 16384 }, - }, - "openai/gpt-4o-search-preview": { - id: "openai/gpt-4o-search-preview", - name: "GPT-4o Search Preview", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.47, output: 5.88 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/gpt-4.1-nano": { - id: "openai/gpt-4.1-nano", - name: "GPT 4.1 Nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1047576, input: 1047576, output: 32768 }, - }, - "openai/o4-mini-high": { - id: "openai/o4-mini-high", - name: "OpenAI o4-mini high", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/o3": { - id: "openai/o3", - name: "OpenAI o3", - family: "o", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.15 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "GPT 5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-5.1-2025-11-13": { - id: "openai/gpt-5.1-2025-11-13", - name: "GPT-5.1 (2025-11-13)", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 1000000, input: 1000000, output: 32768 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.499, output: 9.996 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/o3-mini-low": { - id: "openai/o3-mini-low", - name: "OpenAI o3-mini (Low)", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT 5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-oss-safeguard-20b": { - id: "openai/gpt-oss-safeguard-20b", - name: "GPT OSS Safeguard 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-10-29", - last_updated: "2025-10-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/o3-pro-2025-06-10": { - id: "openai/o3-pro-2025-06-10", - name: "OpenAI o3-pro (2025-06-10)", - family: "o-pro", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-06-10", - last_updated: "2025-06-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9.996, output: 19.992 }, - limit: { context: 200000, input: 200000, output: 100000 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.25 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "openai/gpt-5-chat-latest": { - id: "openai/gpt-5-chat-latest", - name: "GPT 5 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT 4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-10", - last_updated: "2025-09-10", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 1047576, input: 1047576, output: 32768 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT 4.1 Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6 }, - limit: { context: 1047576, input: 1047576, output: 32768 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT 5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 400000, output: 128000 }, - }, - "openai/gpt-4o-2024-11-20": { - id: "openai/gpt-4o-2024-11-20", - name: "GPT-4o (2024-11-20)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-11-20", - last_updated: "2024-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, input: 128000, output: 16384 }, - }, - "VongolaChouko/Starcannon-Unleashed-12B-v1.0": { - id: "VongolaChouko/Starcannon-Unleashed-12B-v1.0", - name: "Mistral Nemo Starcannon 12b v1", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "amazon/nova-lite-v1": { - id: "amazon/nova-lite-v1", - name: "Amazon Nova Lite 1.0", - family: "nova-lite", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0595, output: 0.238 }, - limit: { context: 300000, input: 300000, output: 5120 }, - }, - "amazon/nova-pro-v1": { - id: "amazon/nova-pro-v1", - name: "Amazon Nova Pro 1.0", - family: "nova-pro", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7989999999999999, output: 3.1959999999999997 }, - limit: { context: 300000, input: 300000, output: 32000 }, - }, - "amazon/nova-2-lite-v1": { - id: "amazon/nova-2-lite-v1", - name: "Amazon Nova 2 Lite", - family: "nova", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5099999999999999, output: 4.25 }, - limit: { context: 1000000, input: 1000000, output: 65535 }, - }, - "amazon/nova-micro-v1": { - id: "amazon/nova-micro-v1", - name: "Amazon Nova Micro 1.0", - family: "nova-micro", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0357, output: 0.1394 }, - limit: { context: 128000, input: 128000, output: 5120 }, - }, - "Sao10K/L3.3-70B-Euryale-v2.3": { - id: "Sao10K/L3.3-70B-Euryale-v2.3", - name: "Llama 3.3 70B Euryale", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 20480, input: 20480, output: 16384 }, - }, - "Sao10K/L3.1-70B-Euryale-v2.2": { - id: "Sao10K/L3.1-70B-Euryale-v2.2", - name: "Llama 3.1 70B Euryale", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.306, output: 0.357 }, - limit: { context: 20480, input: 20480, output: 16384 }, - }, - "Sao10K/L3.1-70B-Hanami-x1": { - id: "Sao10K/L3.1-70B-Hanami-x1", - name: "Llama 3.1 70B Hanami", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "Sao10K/L3-8B-Stheno-v3.2": { - id: "Sao10K/L3-8B-Stheno-v3.2", - name: "Sao10K Stheno 8b", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-11-29", - last_updated: "2024-11-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "LatitudeGames/Wayfarer-Large-70B-Llama-3.3": { - id: "LatitudeGames/Wayfarer-Large-70B-Llama-3.3", - name: "Llama 3.3 70B Wayfarer", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-20", - last_updated: "2025-02-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.700000007, output: 0.700000007 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "z-ai/glm-4.6:thinking": { - id: "z-ai/glm-4.6:thinking", - name: "GLM 4.6 Thinking", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.5 }, - limit: { context: 200000, input: 200000, output: 65535 }, - }, - "z-ai/glm-4.5v": { - id: "z-ai/glm-4.5v", - name: "GLM 4.5V", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-22", - last_updated: "2025-11-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 1.7999999999999998 }, - limit: { context: 64000, input: 64000, output: 96000 }, - }, - "z-ai/glm-4.6": { - id: "z-ai/glm-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.5 }, - limit: { context: 200000, input: 200000, output: 65535 }, - }, - "z-ai/glm-4.5v:thinking": { - id: "z-ai/glm-4.5v:thinking", - name: "GLM 4.5V Thinking", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-22", - last_updated: "2025-11-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 1.7999999999999998 }, - limit: { context: 64000, input: 64000, output: 96000 }, - }, - "baidu/ernie-4.5-vl-28b-a3b": { - id: "baidu/ernie-4.5-vl-28b-a3b", - name: "ERNIE 4.5 VL 28B", - family: "ernie", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13999999999999999, output: 0.5599999999999999 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "baidu/ernie-4.5-300b-a47b": { - id: "baidu/ernie-4.5-300b-a47b", - name: "ERNIE 4.5 300B", - family: "ernie", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 1.15 }, - limit: { context: 131072, input: 131072, output: 16384 }, - }, - "dmind/dmind-1": { - id: "dmind/dmind-1", - name: "DMind-1", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.6 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "dmind/dmind-1-mini": { - id: "dmind/dmind-1-mini", - name: "DMind-1-Mini", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.4 }, - limit: { context: 32768, input: 32768, output: 8192 }, - }, - "Infermatic/MN-12B-Inferor-v0.0": { - id: "Infermatic/MN-12B-Inferor-v0.0", - name: "Mistral Nemo Inferor 12B", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25499999999999995, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "meituan-longcat/LongCat-Flash-Chat-FP8": { - id: "meituan-longcat/LongCat-Flash-Chat-FP8", - name: "LongCat Flash", - family: "longcat", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-08-31", - last_updated: "2025-08-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.7 }, - limit: { context: 128000, input: 128000, output: 32768 }, - }, - "meganova-ai/manta-mini-1.0": { - id: "meganova-ai/manta-mini-1.0", - name: "Manta Mini 1.0", - family: "nova", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-20", - last_updated: "2025-12-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.16 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - "meganova-ai/manta-pro-1.0": { - id: "meganova-ai/manta-pro-1.0", - name: "Manta Pro 1.0", - family: "nova", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-20", - last_updated: "2025-12-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.060000000000000005, output: 0.5 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "meganova-ai/manta-flash-1.0": { - id: "meganova-ai/manta-flash-1.0", - name: "Manta Flash 1.0", - family: "nova", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-20", - last_updated: "2025-12-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.16 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "MiniMax M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, input: 204800, output: 131072 }, - }, - "minimax/minimax-01": { - id: "minimax/minimax-01", - name: "MiniMax 01", - family: "minimax", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1394, output: 1.1219999999999999 }, - limit: { context: 1000192, input: 1000192, output: 16384 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 1.32 }, - limit: { context: 200000, input: 200000, output: 131072 }, - }, - "minimax/minimax-m2-her": { - id: "minimax/minimax-m2-her", - name: "MiniMax M2-her", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-01-24", - last_updated: "2026-01-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.30200000000000005, output: 1.2069999999999999 }, - limit: { context: 65532, input: 65532, output: 2048 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, input: 204800, output: 131072 }, - }, - "qwen/Qwen3.6-35B-A3B:thinking": { - id: "qwen/Qwen3.6-35B-A3B:thinking", - name: "Qwen3.6 35B A3B Thinking", - family: "qwen3.6", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2026-04-19", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 1.74 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 258048, input: 258048, output: 65536 }, - }, - "qwen/Qwen3.6-35B-A3B": { - id: "qwen/Qwen3.6-35B-A3B", - name: "Qwen3.6 35B A3B", - family: "qwen3.6", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2026-04-17", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 1.74 }, - limit: { context: 262144, output: 16384 }, - }, - "unsloth/gemma-3-1b-it": { - id: "unsloth/gemma-3-1b-it", - name: "Gemma 3 1B IT", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1003, output: 0.1003 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "unsloth/gemma-3-12b-it": { - id: "unsloth/gemma-3-12b-it", - name: "Gemma 3 12B IT", - family: "unsloth", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.272, output: 0.272 }, - limit: { context: 128000, input: 128000, output: 131072 }, - }, - "unsloth/gemma-3-4b-it": { - id: "unsloth/gemma-3-4b-it", - name: "Gemma 3 4B IT", - family: "unsloth", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "unsloth/gemma-3-27b-it": { - id: "unsloth/gemma-3-27b-it", - name: "Gemma 3 27B IT", - family: "unsloth", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2992, output: 0.2992 }, - limit: { context: 128000, input: 128000, output: 96000 }, - }, - "THUDM/GLM-Z1-9B-0414": { - id: "THUDM/GLM-Z1-9B-0414", - name: "GLM Z1 9B 0414", - family: "glm-z", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 32000, input: 32000, output: 8000 }, - }, - "THUDM/GLM-4-9B-0414": { - id: "THUDM/GLM-4-9B-0414", - name: "GLM 4 9B 0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 32000, input: 32000, output: 8000 }, - }, - "THUDM/GLM-Z1-Rumination-32B-0414": { - id: "THUDM/GLM-Z1-Rumination-32B-0414", - name: "GLM Z1 Rumination 32B 0414", - family: "glm-z", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 32000, input: 32000, output: 65536 }, - }, - "THUDM/GLM-4-32B-0414": { - id: "THUDM/GLM-4-32B-0414", - name: "GLM 4 32B 0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "THUDM/GLM-Z1-32B-0414": { - id: "THUDM/GLM-Z1-32B-0414", - name: "GLM Z1 32B 0414", - family: "glm-z", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Gemini 3 Flash (Preview)", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "google/gemini-flash-1.5": { - id: "google/gemini-flash-1.5", - name: "Gemini 1.5 Flash", - family: "gemini-flash", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-05-14", - last_updated: "2024-05-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0748, output: 0.306 }, - limit: { context: 2000000, input: 2000000, output: 8192 }, - }, - "google/gemini-3-flash-preview-thinking": { - id: "google/gemini-3-flash-preview-thinking", - name: "Gemini 3 Flash Thinking", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 1048756, input: 1048756, output: 65536 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - release_date: "2026-01-26", - last_updated: "2026-01-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.9 }, - limit: { context: 256000, input: 256000, output: 65536 }, - }, - "moonshotai/kimi-k2-instruct": { - id: "moonshotai/kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 2 }, - limit: { context: 256000, input: 256000, output: 8192 }, - }, - "moonshotai/kimi-k2-thinking-original": { - id: "moonshotai/kimi-k2-thinking-original", - name: "Kimi K2 Thinking Original", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "moonshotai/kimi-k2-instruct-0711": { - id: "moonshotai/kimi-k2-instruct-0711", - name: "Kimi K2 0711", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 2 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "moonshotai/Kimi-Dev-72B": { - id: "moonshotai/Kimi-Dev-72B", - name: "Kimi Dev 72B", - family: "kimi", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 128000, input: 128000, output: 131072 }, - }, - "moonshotai/kimi-k2-thinking-turbo-original": { - id: "moonshotai/kimi-k2-thinking-turbo-original", - name: "Kimi K2 Thinking Turbo Original", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.15, output: 8 }, - limit: { context: 256000, input: 256000, output: 16384 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - release_date: "2026-04-16", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.53, output: 2.73 }, - limit: { context: 256000, output: 65536 }, - }, - "moonshotai/kimi-k2.6:thinking": { - id: "moonshotai/kimi-k2.6:thinking", - name: "Kimi K2.6 Thinking", - family: "kimi-thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - release_date: "2026-04-16", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.53, output: 2.73 }, - limit: { context: 256000, output: 65536 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 256000, input: 256000, output: 262144 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 256000, input: 256000, output: 262144 }, - }, - "moonshotai/kimi-k2.5:thinking": { - id: "moonshotai/kimi-k2.5:thinking", - name: "Kimi K2.5 Thinking", - family: "kimi-thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - release_date: "2026-01-26", - last_updated: "2026-01-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.9 }, - limit: { context: 256000, input: 256000, output: 65536 }, - }, - "Tongyi-Zhiwen/QwenLong-L1-32B": { - id: "Tongyi-Zhiwen/QwenLong-L1-32B", - name: "QwenLong L1 32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13999999999999999, output: 0.6 }, - limit: { context: 128000, input: 128000, output: 40960 }, - }, - "nothingiisreal/L3.1-70B-Celeste-V0.1-BF16": { - id: "nothingiisreal/L3.1-70B-Celeste-V0.1-BF16", - name: "Llama 3.1 70B Celeste v0.1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "aion-labs/aion-1.0": { - id: "aion-labs/aion-1.0", - name: "Aion 1.0", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-01", - last_updated: "2025-02-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3.995, output: 7.99 }, - limit: { context: 65536, input: 65536, output: 8192 }, - }, - "aion-labs/aion-rp-llama-3.1-8b": { - id: "aion-labs/aion-rp-llama-3.1-8b", - name: "Llama 3.1 8b (uncensored)", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2006, output: 0.2006 }, - limit: { context: 32768, input: 32768, output: 16384 }, - }, - "aion-labs/aion-1.0-mini": { - id: "aion-labs/aion-1.0-mini", - name: "Aion 1.0 mini (DeepSeek)", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-02-20", - last_updated: "2025-02-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7989999999999999, output: 1.394 }, - limit: { context: 131072, input: 131072, output: 8192 }, - }, - "Alibaba-NLP/Tongyi-DeepResearch-30B-A3B": { - id: "Alibaba-NLP/Tongyi-DeepResearch-30B-A3B", - name: "Tongyi DeepResearch 30B A3B", - family: "yi", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.24000000000000002 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "MiniMaxAI/MiniMax-M1-80k": { - id: "MiniMaxAI/MiniMax-M1-80k", - name: "MiniMax M1 80K", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-06-16", - last_updated: "2025-06-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6052, output: 2.4225000000000003 }, - limit: { context: 1000000, input: 1000000, output: 131072 }, - }, - "anthropic/claude-opus-4.6:thinking:low": { - id: "anthropic/claude-opus-4.6:thinking:low", - name: "Claude 4.6 Opus Thinking Low", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Claude 4.6 Opus", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-sonnet-4.6:thinking": { - id: "anthropic/claude-sonnet-4.6:thinking", - name: "Claude Sonnet 4.6 Thinking", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.993999999999998 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.6:thinking:max": { - id: "anthropic/claude-opus-4.6:thinking:max", - name: "Claude 4.6 Opus Thinking Max", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.6:thinking:medium": { - id: "anthropic/claude-opus-4.6:thinking:medium", - name: "Claude 4.6 Opus Thinking Medium", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.992, output: 14.993999999999998 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.6:thinking": { - id: "anthropic/claude-opus-4.6:thinking", - name: "Claude 4.6 Opus Thinking", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.998, output: 25.007 }, - limit: { context: 1000000, input: 1000000, output: 128000 }, - }, - "abacusai/Dracarys-72B-Instruct": { - id: "abacusai/Dracarys-72B-Instruct", - name: "Llama 3.1 70B Dracarys 2", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-02", - last_updated: "2025-08-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - 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", - name: "EVA Llama 3.33 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.006 }, - 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", - name: "EVA-Qwen2.5-72B-v0.2", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7989999999999999, output: 0.7989999999999999 }, - 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", - name: "EVA-LLaMA-3.33-70B-v0.1", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.006, output: 2.006 }, - 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", - name: "EVA-Qwen2.5-32B-v0.2", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7989999999999999, output: 0.7989999999999999 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "huihui-ai/DeepSeek-R1-Distill-Qwen-32B-abliterated": { - id: "huihui-ai/DeepSeek-R1-Distill-Qwen-32B-abliterated", - name: "DeepSeek R1 Qwen Abliterated", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 1.4 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated": { - id: "huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliterated", - name: "DeepSeek R1 Llama 70B Abliterated", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "huihui-ai/Llama-3.3-70B-Instruct-abliterated": { - id: "huihui-ai/Llama-3.3-70B-Instruct-abliterated", - name: "Llama 3.3 70B Instruct abliterated", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "huihui-ai/Qwen2.5-32B-Instruct-abliterated": { - id: "huihui-ai/Qwen2.5-32B-Instruct-abliterated", - name: "Qwen 2.5 32B Abliterated", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-01-06", - last_updated: "2025-01-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - 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", - name: "Nemotron 3.1 70B abliterated", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 16384, input: 16384, output: 16384 }, - }, - "xiaomi/mimo-v2-flash-thinking-original": { - id: "xiaomi/mimo-v2-flash-thinking-original", - name: "MiMo V2 Flash (Thinking) Original", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.102, output: 0.306 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "xiaomi/mimo-v2-flash-thinking": { - id: "xiaomi/mimo-v2-flash-thinking", - name: "MiMo V2 Flash (Thinking)", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.102, output: 0.306 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "MiMo V2 Flash", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.102, output: 0.306 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "xiaomi/mimo-v2-flash-original": { - id: "xiaomi/mimo-v2-flash-original", - name: "MiMo V2 Flash Original", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.102, output: 0.306 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "tngtech/DeepSeek-TNG-R1T2-Chimera": { - id: "tngtech/DeepSeek-TNG-R1T2-Chimera", - name: "DeepSeek TNG R1T2 Chimera", - family: "tngtech", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.31, output: 0.31 }, - limit: { context: 128000, input: 128000, output: 8192 }, - }, - "tngtech/tng-r1t-chimera": { - id: "tngtech/tng-r1t-chimera", - name: "TNG R1T Chimera", - family: "tngtech", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-11-26", - last_updated: "2025-11-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 128000, input: 128000, output: 65536 }, - }, - "inflatebot/MN-12B-Mag-Mell-R1": { - id: "inflatebot/MN-12B-Mag-Mell-R1", - name: "Mag Mell R1", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.49299999999999994, output: 0.49299999999999994 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - "failspy/Meta-Llama-3-70B-Instruct-abliterated-v3.5": { - id: "failspy/Meta-Llama-3-70B-Instruct-abliterated-v3.5", - name: "Llama 3 70B abliterated", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 8192, input: 8192, output: 8192 }, - }, - }, - }, - abacus: { - id: "abacus", - env: ["ABACUS_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://routellm.abacus.ai/v1", - name: "Abacus", - doc: "https://abacus.ai/help/api", - models: { - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 200000, output: 64000 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 32768 }, - }, - "gemini-3.1-flash-lite-preview": { - id: "gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-01", - last_updated: "2026-03-01", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.3-chat-latest": { - id: "gpt-5.3-chat-latest", - name: "GPT-5.3 Chat Latest", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-01", - last_updated: "2026-03-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 1048576, output: 65536 }, - }, - "llama-3.3-70b-versatile": { - id: "llama-3.3-70b-versatile", - name: "Llama 3.3 70B Versatile", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.59, output: 0.79 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 1048576, output: 65536 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-11-17", - last_updated: "2025-11-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 16384 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - }, - "o3-pro": { - id: "o3-pro", - name: "o3-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-06-10", - last_updated: "2025-06-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 40 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "GPT-4o Mini", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6 }, - limit: { context: 131072, output: 16384 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.2-chat-latest": { - id: "gpt-5.2-chat-latest", - name: "GPT-5.2 Chat Latest", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2026-01-01", - last_updated: "2026-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5.3-codex-xhigh": { - id: "gpt-5.3-codex-xhigh", - name: "GPT-5.3 Codex XHigh", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 256000, output: 16384 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, output: 100000 }, - }, - "grok-4-0709": { - id: "grok-4-0709", - name: "Grok 4", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 256000, output: 16384 }, - }, - "route-llm": { - id: "route-llm", - name: "Route LLM", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-01-01", - last_updated: "2024-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen-2.5-coder-32b": { - id: "qwen-2.5-coder-32b", - name: "Qwen 2.5 Coder 32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-11", - last_updated: "2024-11-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.79, output: 0.79 }, - limit: { context: 128000, output: 8192 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "GPT-5 Codex", - family: "gpt", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-5.1-chat-latest": { - id: "gpt-5.1-chat-latest", - name: "GPT-5.1 Chat Latest", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-14", - last_updated: "2025-05-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - "kimi-k2-turbo-preview": { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo Preview", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 8 }, - limit: { context: 256000, output: 8192 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 200000, output: 128000 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "GPT-4.1 Nano", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1047576, output: 32768 }, - }, - "claude-3-7-sonnet-20250219": { - id: "claude-3-7-sonnet-20250219", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 64000 }, - }, - o3: { - id: "o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-14", - last_updated: "2025-05-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 Mini", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-4o-2024-11-20": { - id: "gpt-4o-2024-11-20", - name: "GPT-4o (2024-11-20)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-11-20", - last_updated: "2024-11-20", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 2000000, output: 16384 }, - }, - "deepseek/deepseek-v3.1": { - id: "deepseek/deepseek-v3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 1.66 }, - limit: { context: 128000, output: 8192 }, - }, - "Qwen/QwQ-32B": { - id: "Qwen/QwQ-32B", - name: "QwQ 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-11-28", - last_updated: "2024-11-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 32768, output: 32768 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.6 }, - limit: { context: 262144, output: 8192 }, - }, - "Qwen/Qwen3-32B": { - id: "Qwen/Qwen3-32B", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.29 }, - limit: { context: 128000, output: 8192 }, - }, - "Qwen/qwen3-coder-480b-a35b-instruct": { - id: "Qwen/qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 1.2 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen2.5-72B-Instruct": { - id: "Qwen/Qwen2.5-72B-Instruct", - name: "Qwen 2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.38 }, - limit: { context: 128000, output: 8192 }, - }, - "zai-org/glm-4.7": { - id: "zai-org/glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 128000, output: 8192 }, - }, - "zai-org/glm-5": { - id: "zai-org/glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/glm-4.5": { - id: "zai-org/glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 128000, output: 8192 }, - }, - "zai-org/glm-4.6": { - id: "zai-org/glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 128000, output: 8192 }, - }, - "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": { - id: "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", - name: "Llama 3.1 405B Instruct Turbo", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3.5, output: 3.5 }, - limit: { context: 128000, output: 4096 }, - }, - "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": { - id: "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", - name: "Llama 4 Maverick 17B 128E Instruct FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.59 }, - limit: { context: 1000000, output: 32768 }, - }, - "meta-llama/Meta-Llama-3.1-8B-Instruct": { - id: "meta-llama/Meta-Llama-3.1-8B-Instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.05 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-ai/DeepSeek-R1": { - id: "deepseek-ai/DeepSeek-R1", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 7 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-15", - last_updated: "2025-06-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.4 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT-OSS 120B", - family: "gpt-oss", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.44 }, - limit: { context: 128000, output: 32768 }, - }, - }, - }, - "perplexity-agent": { - id: "perplexity-agent", - env: ["PERPLEXITY_API_KEY"], - npm: "@ai-sdk/openai", - api: "https://api.perplexity.ai/v1", - name: "Perplexity Agent", - doc: "https://docs.perplexity.ai/docs/agent-api/models", - models: { - "perplexity/sonar": { - id: "perplexity/sonar", - name: "Sonar", - family: "sonar", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2.5, cache_read: 0.0625 }, - limit: { context: 128000, output: 8192 }, - }, - "xai/grok-4-1-fast-non-reasoning": { - id: "xai/grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "Nemotron 3 Super 120B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2.5 }, - limit: { context: 1000000, output: 32000 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "google/gemini-3.1-pro-preview": { - id: "google/gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.5, - output: 3, - cache_read: 0.05, - context_over_200k: { input: 0.5, output: 3, cache_read: 0.05 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03 }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic/claude-haiku-4-5": { - id: "anthropic/claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4-6": { - id: "anthropic/claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4-7": { - id: "anthropic/claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4-5": { - id: "anthropic/claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4-6": { - id: "anthropic/claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5 }, - limit: { context: 200000, output: 128000 }, - }, - "anthropic/claude-sonnet-4-5": { - id: "anthropic/claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3 }, - limit: { context: 200000, output: 64000 }, - }, - }, - }, - "siliconflow-cn": { - id: "siliconflow-cn", - env: ["SILICONFLOW_CN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.siliconflow.cn/v1", - name: "SiliconFlow (China)", - doc: "https://cloud.siliconflow.com/models", - models: { - "Kwaipilot/KAT-Dev": { - id: "Kwaipilot/KAT-Dev", - name: "Kwaipilot/KAT-Dev", - family: "kat-coder", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-27", - last_updated: "2026-01-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 128000, output: 128000 }, - }, - "Qwen/Qwen3.5-397B-A17B": { - id: "Qwen/Qwen3.5-397B-A17B", - name: "Qwen/Qwen3.5-397B-A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 1.74 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.5-35B-A3B": { - id: "Qwen/Qwen3.5-35B-A3B", - name: "Qwen/Qwen3.5-35B-A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-25", - last_updated: "2026-02-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.23, output: 1.86 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.5-122B-A10B": { - id: "Qwen/Qwen3.5-122B-A10B", - name: "Qwen/Qwen3.5-122B-A10B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 2.32 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.5-9B": { - id: "Qwen/Qwen3.5-9B", - name: "Qwen/Qwen3.5-9B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 1.74 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.5-27B": { - id: "Qwen/Qwen3.5-27B", - name: "Qwen/Qwen3.5-27B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-25", - last_updated: "2026-02-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 2.09 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.5-4B": { - id: "Qwen/Qwen3.5-4B", - name: "Qwen/Qwen3.5-4B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3.6-35B-A3B": { - id: "Qwen/Qwen3.6-35B-A3B", - name: "Qwen/Qwen3.6-35B-A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.23, output: 1.86 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen2.5-72B-Instruct": { - id: "Qwen/Qwen2.5-72B-Instruct", - name: "Qwen/Qwen2.5-72B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-8B-Instruct": { - id: "Qwen/Qwen3-VL-8B-Instruct", - name: "Qwen/Qwen3-VL-8B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.68 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-32B-Instruct": { - id: "Qwen/Qwen3-VL-32B-Instruct", - name: "Qwen/Qwen3-VL-32B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-21", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-30B-A3B-Thinking": { - id: "Qwen/Qwen3-VL-30B-A3B-Thinking", - name: "Qwen/Qwen3-VL-30B-A3B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-11", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-14B-Instruct": { - id: "Qwen/Qwen2.5-14B-Instruct", - name: "Qwen/Qwen2.5-14B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Instruct": { - id: "Qwen/Qwen3-VL-235B-A22B-Instruct", - name: "Qwen/Qwen3-VL-235B-A22B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Thinking": { - id: "Qwen/Qwen3-Next-80B-A3B-Thinking", - name: "Qwen/Qwen3-Next-80B-A3B-Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-25", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-VL-32B-Instruct": { - id: "Qwen/Qwen2.5-VL-32B-Instruct", - name: "Qwen/Qwen2.5-VL-32B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-24", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Thinking": { - id: "Qwen/Qwen3-Omni-30B-A3B-Thinking", - name: "Qwen/Qwen3-Omni-30B-A3B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen/Qwen3-235B-A22B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-32B-Instruct": { - id: "Qwen/Qwen2.5-32B-Instruct", - name: "Qwen/Qwen2.5-32B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-19", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen2.5-72B-Instruct-128K": { - id: "Qwen/Qwen2.5-72B-Instruct-128K", - name: "Qwen/Qwen2.5-72B-Instruct-128K", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 131000, output: 4000 }, - }, - "Qwen/Qwen3-14B": { - id: "Qwen/Qwen3-14B", - name: "Qwen/Qwen3-14B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Instruct": { - id: "Qwen/Qwen3-Omni-30B-A3B-Instruct", - name: "Qwen/Qwen3-Omni-30B-A3B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/Qwen3-Coder-30B-A3B-Instruct": { - id: "Qwen/Qwen3-Coder-30B-A3B-Instruct", - name: "Qwen/Qwen3-Coder-30B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-01", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-32B": { - id: "Qwen/Qwen3-32B", - name: "Qwen/Qwen3-32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen/Qwen3-235B-A22B-Instruct-2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-23", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen/Qwen3-30B-A3B-Instruct-2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.3 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-8B": { - id: "Qwen/Qwen3-8B", - name: "Qwen/Qwen3-8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.06 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Instruct": { - id: "Qwen/Qwen3-Next-80B-A3B-Instruct", - name: "Qwen/Qwen3-Next-80B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-8B-Thinking": { - id: "Qwen/Qwen3-VL-8B-Thinking", - name: "Qwen/Qwen3-VL-8B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 2 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Captioner": { - id: "Qwen/Qwen3-Omni-30B-A3B-Captioner", - name: "Qwen/Qwen3-Omni-30B-A3B-Captioner", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/QwQ-32B": { - id: "Qwen/QwQ-32B", - name: "Qwen/QwQ-32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-06", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.58 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-VL-30B-A3B-Instruct": { - id: "Qwen/Qwen3-VL-30B-A3B-Instruct", - name: "Qwen/Qwen3-VL-30B-A3B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-05", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-Coder-32B-Instruct": { - id: "Qwen/Qwen2.5-Coder-32B-Instruct", - name: "Qwen/Qwen2.5-Coder-32B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-11-11", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen2.5-7B-Instruct": { - id: "Qwen/Qwen2.5-7B-Instruct", - name: "Qwen/Qwen2.5-7B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Thinking": { - id: "Qwen/Qwen3-VL-235B-A22B-Thinking", - name: "Qwen/Qwen3-VL-235B-A22B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 3.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-30B-A3B-Thinking-2507": { - id: "Qwen/Qwen3-30B-A3B-Thinking-2507", - name: "Qwen/Qwen3-30B-A3B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.3 }, - limit: { context: 262000, output: 131000 }, - }, - "Qwen/Qwen3-VL-32B-Thinking": { - id: "Qwen/Qwen3-VL-32B-Thinking", - name: "Qwen/Qwen3-VL-32B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-21", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-VL-72B-Instruct": { - id: "Qwen/Qwen2.5-VL-72B-Instruct", - name: "Qwen/Qwen2.5-VL-72B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-28", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 131000, output: 4000 }, - }, - "stepfun-ai/Step-3.5-Flash": { - id: "stepfun-ai/Step-3.5-Flash", - name: "stepfun-ai/Step-3.5-Flash", - family: "step", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 262000, output: 262000 }, - }, - "zai-org/GLM-4.5V": { - id: "zai-org/GLM-4.5V", - name: "zai-org/GLM-4.5V", - family: "glm", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.86 }, - limit: { context: 66000, output: 66000 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "zai-org/GLM-4.6", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.9 }, - limit: { context: 205000, output: 205000 }, - }, - "zai-org/GLM-4.6V": { - id: "zai-org/GLM-4.6V", - name: "zai-org/GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-07", - last_updated: "2025-12-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 131000, output: 131000 }, - }, - "zai-org/GLM-4.5-Air": { - id: "zai-org/GLM-4.5-Air", - name: "zai-org/GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.86 }, - limit: { context: 131000, output: 131000 }, - }, - "inclusionAI/Ling-flash-2.0": { - id: "inclusionAI/Ling-flash-2.0", - name: "inclusionAI/Ling-flash-2.0", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "inclusionAI/Ling-mini-2.0": { - id: "inclusionAI/Ling-mini-2.0", - name: "inclusionAI/Ling-mini-2.0", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-10", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131000, output: 131000 }, - }, - "inclusionAI/Ring-flash-2.0": { - id: "inclusionAI/Ring-flash-2.0", - name: "inclusionAI/Ring-flash-2.0", - family: "ring", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "ascend-tribe/pangu-pro-moe": { - id: "ascend-tribe/pangu-pro-moe", - name: "ascend-tribe/pangu-pro-moe", - family: "pangu", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-07-02", - last_updated: "2026-01-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 128000, output: 128000 }, - }, - "tencent/Hunyuan-MT-7B": { - id: "tencent/Hunyuan-MT-7B", - name: "tencent/Hunyuan-MT-7B", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 33000, output: 33000 }, - }, - "tencent/Hunyuan-A13B-Instruct": { - id: "tencent/Hunyuan-A13B-Instruct", - name: "tencent/Hunyuan-A13B-Instruct", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "Pro/zai-org/GLM-4.7": { - id: "Pro/zai-org/GLM-4.7", - name: "Pro/zai-org/GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 205000, output: 205000 }, - }, - "Pro/zai-org/GLM-5.1": { - id: "Pro/zai-org/GLM-5.1", - name: "Pro/zai-org/GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_write: 0 }, - limit: { context: 205000, output: 205000 }, - }, - "Pro/zai-org/GLM-5": { - id: "Pro/zai-org/GLM-5", - name: "Pro/zai-org/GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 205000, output: 205000 }, - }, - "Pro/deepseek-ai/DeepSeek-V3": { - id: "Pro/deepseek-ai/DeepSeek-V3", - name: "Pro/deepseek-ai/DeepSeek-V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-26", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "Pro/deepseek-ai/DeepSeek-R1": { - id: "Pro/deepseek-ai/DeepSeek-R1", - name: "Pro/deepseek-ai/DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.18 }, - limit: { context: 164000, output: 164000 }, - }, - "Pro/deepseek-ai/DeepSeek-V3.2": { - id: "Pro/deepseek-ai/DeepSeek-V3.2", - name: "Pro/deepseek-ai/DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.42 }, - limit: { context: 164000, output: 164000 }, - }, - "Pro/deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "Pro/deepseek-ai/DeepSeek-V3.1-Terminus", - name: "Pro/deepseek-ai/DeepSeek-V3.1-Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "Pro/moonshotai/Kimi-K2-Thinking": { - id: "Pro/moonshotai/Kimi-K2-Thinking", - name: "Pro/moonshotai/Kimi-K2-Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-11-07", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.55, output: 2.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Pro/moonshotai/Kimi-K2.6": { - id: "Pro/moonshotai/Kimi-K2.6", - name: "Pro/moonshotai/Kimi-K2.6", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262000, output: 262000 }, - }, - "Pro/moonshotai/Kimi-K2-Instruct-0905": { - id: "Pro/moonshotai/Kimi-K2-Instruct-0905", - name: "Pro/moonshotai/Kimi-K2-Instruct-0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-08", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 262000, output: 262000 }, - }, - "Pro/moonshotai/Kimi-K2.5": { - id: "Pro/moonshotai/Kimi-K2.5", - name: "Pro/moonshotai/Kimi-K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.25 }, - limit: { context: 262000, output: 262000 }, - }, - "Pro/MiniMaxAI/MiniMax-M2.5": { - id: "Pro/MiniMaxAI/MiniMax-M2.5", - name: "Pro/MiniMaxAI/MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.22 }, - limit: { context: 192000, output: 131000 }, - }, - "Pro/MiniMaxAI/MiniMax-M2.1": { - id: "Pro/MiniMaxAI/MiniMax-M2.1", - name: "Pro/MiniMaxAI/MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 197000, output: 131000 }, - }, - "PaddlePaddle/PaddleOCR-VL": { - id: "PaddlePaddle/PaddleOCR-VL", - name: "PaddlePaddle/PaddleOCR-VL", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-16", - last_updated: "2025-10-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 16384, output: 16384 }, - }, - "PaddlePaddle/PaddleOCR-VL-1.5": { - id: "PaddlePaddle/PaddleOCR-VL-1.5", - name: "PaddlePaddle/PaddleOCR-VL-1.5", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 16384, output: 16384 }, - }, - "deepseek-ai/DeepSeek-OCR": { - id: "deepseek-ai/DeepSeek-OCR", - name: "deepseek-ai/DeepSeek-OCR", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-20", - last_updated: "2025-10-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus", - name: "deepseek-ai/DeepSeek-V3.1-Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "deepseek-ai/DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.42 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B": { - id: "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", - name: "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-R1": { - id: "deepseek-ai/DeepSeek-R1", - name: "deepseek-ai/DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.18 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B": { - id: "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - name: "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 131000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-V3": { - id: "deepseek-ai/DeepSeek-V3", - name: "deepseek-ai/DeepSeek-V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-26", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/deepseek-vl2": { - id: "deepseek-ai/deepseek-vl2", - name: "deepseek-ai/deepseek-vl2", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-13", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 4000, output: 4000 }, - }, - "baidu/ERNIE-4.5-300B-A47B": { - id: "baidu/ERNIE-4.5-300B-A47B", - name: "baidu/ERNIE-4.5-300B-A47B", - family: "ernie", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-02", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 131000, output: 131000 }, - }, - "THUDM/GLM-Z1-32B-0414": { - id: "THUDM/GLM-Z1-32B-0414", - name: "THUDM/GLM-Z1-32B-0414", - family: "glm-z", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "THUDM/GLM-4-32B-0414": { - id: "THUDM/GLM-4-32B-0414", - name: "THUDM/GLM-4-32B-0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 33000, output: 33000 }, - }, - "THUDM/GLM-4-9B-0414": { - id: "THUDM/GLM-4-9B-0414", - name: "THUDM/GLM-4-9B-0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.086, output: 0.086 }, - limit: { context: 33000, output: 33000 }, - }, - "THUDM/GLM-Z1-9B-0414": { - id: "THUDM/GLM-Z1-9B-0414", - name: "THUDM/GLM-Z1-9B-0414", - family: "glm-z", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.086, output: 0.086 }, - limit: { context: 131000, output: 131000 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "moonshotai/Kimi-K2-Instruct-0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-08", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 262000, output: 262000 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "moonshotai/Kimi-K2-Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-11-07", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.55, output: 2.5 }, - limit: { context: 262000, output: 262000 }, - }, - "ByteDance-Seed/Seed-OSS-36B-Instruct": { - id: "ByteDance-Seed/Seed-OSS-36B-Instruct", - name: "ByteDance-Seed/Seed-OSS-36B-Instruct", - family: "seed", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-04", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.57 }, - limit: { context: 262000, output: 262000 }, - }, - }, - }, - submodel: { - id: "submodel", - env: ["SUBMODEL_INSTAGEN_ACCESS_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://llm.submodel.ai/v1", - name: "submodel", - doc: "https://submodel.gitbook.io", - models: { - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.3 }, - limit: { context: 262144, output: 131072 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3 235B A22B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 262144, output: 131072 }, - }, - "zai-org/GLM-4.5-Air": { - id: "zai-org/GLM-4.5-Air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 131072, output: 131072 }, - }, - "zai-org/GLM-4.5-FP8": { - id: "zai-org/GLM-4.5-FP8", - name: "GLM 4.5 FP8", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 131072, output: 131072 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 75000, output: 163840 }, - }, - "deepseek-ai/DeepSeek-V3-0324": { - id: "deepseek-ai/DeepSeek-V3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 75000, output: 163840 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.15 }, - limit: { context: 75000, output: 163840 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-23", - last_updated: "2025-08-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 131072, output: 32768 }, - }, - }, - }, - "minimax-coding-plan": { - id: "minimax-coding-plan", - env: ["MINIMAX_API_KEY"], - npm: "@ai-sdk/anthropic", - api: "https://api.minimax.io/anthropic/v1", - name: "MiniMax Coding Plan (minimax.io)", - doc: "https://platform.minimax.io/docs/coding-plan/intro", - models: { - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 196608, output: 128000 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7-highspeed": { - id: "MiniMax-M2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.5-highspeed": { - id: "MiniMax-M2.5-highspeed", - name: "MiniMax-M2.5-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - perplexity: { - id: "perplexity", - env: ["PERPLEXITY_API_KEY"], - npm: "@ai-sdk/perplexity", - name: "Perplexity", - doc: "https://docs.perplexity.ai", - models: { - "sonar-pro": { - id: "sonar-pro", - name: "Sonar Pro", - family: "sonar-pro", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8192 }, - }, - "sonar-deep-research": { - id: "sonar-deep-research", - name: "Perplexity Sonar Deep Research", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-02-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, reasoning: 3 }, - limit: { context: 128000, output: 32768 }, - }, - sonar: { - id: "sonar", - name: "Sonar", - family: "sonar", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 128000, output: 4096 }, - }, - "sonar-reasoning-pro": { - id: "sonar-reasoning-pro", - name: "Sonar Reasoning Pro", - family: "sonar-reasoning", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 128000, output: 4096 }, - }, - }, - }, - deepseek: { - id: "deepseek", - env: ["DEEPSEEK_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.deepseek.com", - name: "DeepSeek", - doc: "https://api-docs.deepseek.com/quick_start/pricing", - models: { - "deepseek-chat": { - id: "deepseek-chat", - name: "DeepSeek Chat", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-12-01", - last_updated: "2026-02-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek-reasoner": { - id: "deepseek-reasoner", - name: "DeepSeek Reasoner", - family: "deepseek-thinking", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-09", - release_date: "2025-12-01", - last_updated: "2026-02-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - llama: { - id: "llama", - env: ["LLAMA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.llama.com/compat/v1/", - name: "Llama", - doc: "https://llama.developer.meta.com/docs/models", - models: { - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cerebras-llama-4-maverick-17b-128e-instruct": { - id: "cerebras-llama-4-maverick-17b-128e-instruct", - name: "Cerebras-Llama-4-Maverick-17B-128E-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "llama-3.3-8b-instruct": { - id: "llama-3.3-8b-instruct", - name: "Llama-3.3-8B-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cerebras-llama-4-scout-17b-16e-instruct": { - id: "cerebras-llama-4-scout-17b-16e-instruct", - name: "Cerebras-Llama-4-Scout-17B-16E-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "groq-llama-4-maverick-17b-128e-instruct": { - id: "groq-llama-4-maverick-17b-128e-instruct", - name: "Groq-Llama-4-Maverick-17B-128E-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "llama-4-scout-17b-16e-instruct-fp8": { - id: "llama-4-scout-17b-16e-instruct-fp8", - name: "Llama-4-Scout-17B-16E-Instruct-FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "llama-4-maverick-17b-128e-instruct-fp8": { - id: "llama-4-maverick-17b-128e-instruct-fp8", - name: "Llama-4-Maverick-17B-128E-Instruct-FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - }, - }, - openrouter: { - id: "openrouter", - env: ["OPENROUTER_API_KEY"], - npm: "@openrouter/ai-sdk-provider", - api: "https://openrouter.ai/api/v1", - name: "OpenRouter", - doc: "https://openrouter.ai/models", - models: { - "liquid/lfm-2.5-1.2b-instruct:free": { - id: "liquid/lfm-2.5-1.2b-instruct:free", - name: "LFM2.5-1.2B-Instruct (free)", - family: "liquid", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2026-01-20", - last_updated: "2026-01-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 32768 }, - }, - "liquid/lfm-2.5-1.2b-thinking:free": { - id: "liquid/lfm-2.5-1.2b-thinking:free", - name: "LFM2.5-1.2B-Thinking (free)", - family: "liquid", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2026-01-20", - last_updated: "2026-01-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 32768 }, - }, - "deepseek/deepseek-chat-v3.1": { - id: "deepseek/deepseek-chat-v3.1", - name: "DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-r1-distill-llama-70b": { - id: "deepseek/deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-01-23", - last_updated: "2025-01-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 8192 }, - }, - "deepseek/deepseek-r1": { - id: "deepseek/deepseek-r1", - name: "DeepSeek: R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5 }, - limit: { context: 64000, output: 16000 }, - }, - "deepseek/deepseek-v3.2-speciale": { - id: "deepseek/deepseek-v3.2-speciale", - name: "DeepSeek V3.2 Speciale", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 0.4 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v3.1-terminus:exacto": { - id: "deepseek/deepseek-v3.1-terminus:exacto", - name: "DeepSeek V3.1 Terminus (exacto)", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 131072, output: 65536 }, - }, - "deepseek/deepseek-chat-v3-0324": { - id: "deepseek/deepseek-chat-v3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 16384, output: 8192 }, - }, - "deepseek/deepseek-v3.1-terminus": { - id: "deepseek/deepseek-v3.1-terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 131072, output: 65536 }, - }, - "openrouter/owl-alpha": { - id: "openrouter/owl-alpha", - name: "Owl Alpha", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1048756, output: 262144 }, - status: "alpha", - }, - "openrouter/pareto-code": { - id: "openrouter/pareto-code", - name: "Pareto Code Router", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 200000 }, - }, - "openrouter/elephant-alpha": { - id: "openrouter/elephant-alpha", - name: "Elephant (free)", - family: "elephant", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-13", - last_updated: "2026-04-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "openrouter/free": { - id: "openrouter/free", - name: "Free Models Router", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, input: 200000, output: 8000 }, - }, - "arcee-ai/trinity-large-thinking": { - id: "arcee-ai/trinity-large-thinking", - name: "Trinity Large Thinking", - family: "trinity", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.85 }, - limit: { context: 262144, output: 80000 }, - }, - "arcee-ai/trinity-large-preview:free": { - id: "arcee-ai/trinity-large-preview:free", - name: "Trinity Large Preview", - family: "trinity", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-01-28", - last_updated: "2026-01-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "cognitivecomputations/dolphin-mistral-24b-venice-edition:free": { - id: "cognitivecomputations/dolphin-mistral-24b-venice-edition:free", - name: "Uncensored (free)", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-07-09", - last_updated: "2026-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 32768 }, - }, - "bytedance-seed/seedream-4.5": { - id: "bytedance-seed/seedream-4.5", - name: "Seedream 4.5", - family: "seed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-23", - last_updated: "2026-01-31", - modalities: { input: ["image", "text"], output: ["image"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 4096, output: 4096 }, - }, - "black-forest-labs/flux.2-max": { - id: "black-forest-labs/flux.2-max", - name: "FLUX.2 Max", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-16", - last_updated: "2026-01-31", - modalities: { input: ["image", "text"], output: ["image"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 46864, output: 46864 }, - }, - "black-forest-labs/flux.2-flex": { - id: "black-forest-labs/flux.2-flex", - name: "FLUX.2 Flex", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-25", - last_updated: "2026-01-31", - modalities: { input: ["image", "text"], output: ["image"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 67344, output: 67344 }, - }, - "black-forest-labs/flux.2-pro": { - id: "black-forest-labs/flux.2-pro", - name: "FLUX.2 Pro", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-11-25", - last_updated: "2026-01-31", - modalities: { input: ["image", "text"], output: ["image"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 46864, output: 46864 }, - }, - "black-forest-labs/flux.2-klein-4b": { - id: "black-forest-labs/flux.2-klein-4b", - name: "FLUX.2 Klein 4B", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2026-01-14", - last_updated: "2026-01-31", - modalities: { input: ["image", "text"], output: ["image"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 40960, output: 40960 }, - }, - "nousresearch/hermes-3-llama-3.1-405b:free": { - id: "nousresearch/hermes-3-llama-3.1-405b:free", - name: "Hermes 3 405B Instruct (free)", - family: "hermes", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-08-16", - last_updated: "2024-08-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "nousresearch/hermes-4-405b": { - id: "nousresearch/hermes-4-405b", - name: "Hermes 4 405B", - family: "hermes", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-08-25", - last_updated: "2025-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 131072, output: 131072 }, - }, - "nousresearch/hermes-4-70b": { - id: "nousresearch/hermes-4-70b", - name: "Hermes 4 70B", - family: "hermes", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-08-25", - last_updated: "2025-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4 }, - limit: { context: 131072, output: 131072 }, - }, - "stepfun/step-3.5-flash": { - id: "stepfun/step-3.5-flash", - name: "Step 3.5 Flash", - family: "step", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.02 }, - limit: { context: 256000, output: 256000 }, - }, - "mistralai/mistral-small-3.1-24b-instruct": { - id: "mistralai/mistral-small-3.1-24b-instruct", - name: "Mistral Small 3.1 24B Instruct", - family: "mistral-small", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-17", - last_updated: "2025-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "mistralai/devstral-2512": { - id: "mistralai/devstral-2512", - name: "Devstral 2 2512", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-09-12", - last_updated: "2025-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/codestral-2508": { - id: "mistralai/codestral-2508", - name: "Codestral 2508", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 256000 }, - }, - "mistralai/mistral-medium-3.1": { - id: "mistralai/mistral-medium-3.1", - name: "Mistral Medium 3.1", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/mistral-small-2603": { - id: "mistralai/mistral-small-2603", - name: "Mistral Small 4", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/mistral-medium-3": { - id: "mistralai/mistral-medium-3", - name: "Mistral Medium 3", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 131072 }, - }, - "mistralai/devstral-small-2505": { - id: "mistralai/devstral-small-2505", - name: "Devstral Small", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.12 }, - limit: { context: 128000, output: 128000 }, - }, - "mistralai/mistral-small-3.2-24b-instruct": { - id: "mistralai/mistral-small-3.2-24b-instruct", - name: "Mistral Small 3.2 24B Instruct", - family: "mistral-small", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-06-20", - last_updated: "2025-06-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 96000, output: 8192 }, - }, - "mistralai/devstral-medium-2507": { - id: "mistralai/devstral-medium-2507", - name: "Devstral Medium", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 131072 }, - }, - "mistralai/devstral-small-2507": { - id: "mistralai/devstral-small-2507", - name: "Devstral Small 1.1", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 131072, output: 131072 }, - }, - "meta-llama/llama-3.2-11b-vision-instruct": { - id: "meta-llama/llama-3.2-11b-vision-instruct", - name: "Llama 3.2 11B Vision Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "meta-llama/llama-3.2-3b-instruct:free": { - id: "meta-llama/llama-3.2-3b-instruct:free", - name: "Llama 3.2 3B Instruct (free)", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "meta-llama/llama-3.3-70b-instruct:free": { - id: "meta-llama/llama-3.3-70b-instruct:free", - name: "Llama 3.3 70B Instruct (free)", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "x-ai/grok-4.20-multi-agent-beta": { - id: "x-ai/grok-4.20-multi-agent-beta", - name: "Grok 4.20 Multi - Agent Beta", - family: "grok", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-12", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12 } }, - limit: { context: 2000000, output: 30000 }, - status: "beta", - }, - "x-ai/grok-4-fast": { - id: "x-ai/grok-4-fast", - name: "Grok 4 Fast", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05, cache_write: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "x-ai/grok-code-fast-1": { - id: "x-ai/grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "x-ai/grok-3-beta": { - id: "x-ai/grok-3-beta", - name: "Grok 3 Beta", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75, cache_write: 15 }, - limit: { context: 131072, output: 8192 }, - }, - "x-ai/grok-4": { - id: "x-ai/grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75, cache_write: 15 }, - limit: { context: 256000, output: 64000 }, - }, - "x-ai/grok-3-mini": { - id: "x-ai/grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075, cache_write: 0.5 }, - limit: { context: 131072, output: 8192 }, - }, - "x-ai/grok-4.1-fast": { - id: "x-ai/grok-4.1-fast", - name: "Grok 4.1 Fast", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05, cache_write: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "x-ai/grok-4.20-beta": { - id: "x-ai/grok-4.20-beta", - name: "Grok 4.20 Beta", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-12", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12 } }, - limit: { context: 2000000, output: 30000 }, - status: "beta", - }, - "x-ai/grok-3-mini-beta": { - id: "x-ai/grok-3-mini-beta", - name: "Grok 3 Mini Beta", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075, cache_write: 0.5 }, - limit: { context: 131072, output: 8192 }, - }, - "x-ai/grok-3": { - id: "x-ai/grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75, cache_write: 15 }, - limit: { context: 131072, output: 8192 }, - }, - "tencent/hy3-preview": { - id: "tencent/hy3-preview", - name: "Hy3 preview", - family: "Hy", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.066, output: 0.26, cache_read: 0.029, cache_write: 0.029 }, - limit: { context: 256000, output: 64000 }, - }, - "poolside/laguna-m.1:free": { - id: "poolside/laguna-m.1:free", - name: "Laguna M.1", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "poolside/laguna-xs.2:free": { - id: "poolside/laguna-xs.2:free", - name: "Laguna XS.2", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "prime-intellect/intellect-3": { - id: "prime-intellect/intellect-3", - name: "Intellect 3", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 131072, output: 8192 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "Nemotron 3 Super", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free": { - id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", - name: "Nemotron 3 Nano Omni (free)", - family: "nemotron", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-28", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 65536 }, - }, - "nvidia/nemotron-3-nano-30b-a3b:free": { - id: "nvidia/nemotron-3-nano-30b-a3b:free", - name: "Nemotron 3 Nano 30B A3B (free)", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-12-14", - last_updated: "2026-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 256000 }, - }, - "nvidia/nemotron-nano-9b-v2:free": { - id: "nvidia/nemotron-nano-9b-v2:free", - name: "Nemotron Nano 9B V2 (free)", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-09-05", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - }, - "nvidia/nemotron-3-super-120b-a12b:free": { - id: "nvidia/nemotron-3-super-120b-a12b:free", - name: "Nemotron 3 Super (free)", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/nemotron-nano-9b-v2": { - id: "nvidia/nemotron-nano-9b-v2", - name: "nvidia-nemotron-nano-9b-v2", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-08-18", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.16 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/nemotron-nano-12b-v2-vl:free": { - id: "nvidia/nemotron-nano-12b-v2-vl:free", - name: "Nemotron Nano 12B 2 VL (free)", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-10-28", - last_updated: "2026-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - }, - "inception/mercury-edit-2": { - id: "inception/mercury-edit-2", - name: "Mercury Edit 2", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 8192 }, - }, - "inception/mercury-2": { - id: "inception/mercury-2", - name: "Mercury 2", - family: "mercury", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-04", - last_updated: "2026-03-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 50000 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "GPT-5.1-Codex-Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-chat": { - id: "openai/gpt-5.2-chat", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-oss-120b:exacto": { - id: "openai/gpt-oss-120b:exacto", - name: "GPT OSS 120B (exacto)", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.24 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-5-chat": { - id: "openai/gpt-5-chat", - name: "GPT-5 Chat (latest)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT-5.2 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT-5.3-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-20b:free": { - id: "openai/gpt-oss-20b:free", - name: "gpt-oss-20b (free)", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2026-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.4-mini": { - id: "openai/gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1-chat": { - id: "openai/gpt-5.1-chat", - name: "GPT-5.1 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "o4 Mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-nano": { - id: "openai/gpt-5.4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT-5.1-Codex-Mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 100000 }, - }, - "openai/gpt-5-image": { - id: "openai/gpt-5-image", - name: "GPT-5 Image", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-10-14", - last_updated: "2025-10-14", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 5, output: 10, cache_read: 1.25 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, cache_read: 30 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.2 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, output: 272000 }, - }, - "openai/gpt-oss-120b:free": { - id: "openai/gpt-oss-120b:free", - name: "gpt-oss-120b (free)", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-safeguard-20b": { - id: "openai/gpt-oss-safeguard-20b", - name: "GPT OSS Safeguard 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-29", - last_updated: "2025-10-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.072, output: 0.28 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT-4.1 Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "z-ai/glm-4.7": { - id: "z-ai/glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11 }, - limit: { context: 204800, output: 131072 }, - }, - "z-ai/glm-4.5-air:free": { - id: "z-ai/glm-4.5-air:free", - name: "GLM 4.5 Air (free)", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 96000 }, - }, - "z-ai/glm-5": { - id: "z-ai/glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202752, output: 131000 }, - }, - "z-ai/glm-5.1": { - id: "z-ai/glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4.5": { - id: "z-ai/glm-4.5", - name: "GLM 4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 128000, output: 96000 }, - }, - "z-ai/glm-4.6:exacto": { - id: "z-ai/glm-4.6:exacto", - name: "GLM 4.6 (exacto)", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.9, cache_read: 0.11 }, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/glm-4.5-air": { - id: "z-ai/glm-4.5-air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 128000, output: 96000 }, - }, - "z-ai/glm-5-turbo": { - id: "z-ai/glm-5-turbo", - name: "GLM-5-Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.96, output: 3.2, cache_read: 0.192, cache_write: 0 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4.5v": { - id: "z-ai/glm-4.5v", - name: "GLM 4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 64000, output: 16384 }, - }, - "z-ai/glm-4.6": { - id: "z-ai/glm-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11 }, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/glm-4.7-flash": { - id: "z-ai/glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4 }, - limit: { context: 200000, output: 65535 }, - }, - "sourceful/riverflow-v2-standard-preview": { - id: "sourceful/riverflow-v2-standard-preview", - name: "Riverflow V2 Standard Preview", - family: "sourceful", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-08", - last_updated: "2026-01-28", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 8192 }, - }, - "sourceful/riverflow-v2-fast-preview": { - id: "sourceful/riverflow-v2-fast-preview", - name: "Riverflow V2 Fast Preview", - family: "sourceful", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-08", - last_updated: "2026-01-28", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 8192 }, - }, - "sourceful/riverflow-v2-max-preview": { - id: "sourceful/riverflow-v2-max-preview", - name: "Riverflow V2 Max Preview", - family: "sourceful", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-08", - last_updated: "2026-01-28", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 8192 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "MiniMax M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "MiniMax M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2025-10-23", - last_updated: "2025-10-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.15, cache_read: 0.28, cache_write: 1.15 }, - limit: { context: 196600, output: 118000 }, - }, - "minimax/minimax-01": { - id: "minimax/minimax-01", - name: "MiniMax-01", - family: "minimax", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 1000000, output: 1000000 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2.5:free": { - id: "minimax/minimax-m2.5:free", - name: "MiniMax M2.5 (free)", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m1": { - id: "minimax/minimax-m1", - name: "MiniMax M1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2.2 }, - limit: { context: 1000000, output: 40000 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen/qwen3-coder-plus": { - id: "qwen/qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 3.25, cache_read: 0.13, cache_write: 0.8125 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen2.5-vl-72b-instruct": { - id: "qwen/qwen2.5-vl-72b-instruct", - name: "Qwen2.5 VL 72B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-02-01", - last_updated: "2025-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "qwen/qwen-plus": { - id: "qwen/qwen-plus", - name: "Qwen: Qwen-Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.26, output: 0.78, cache_read: 0.052, cache_write: 0.325 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen/qwen3.5-flash-02-23": { - id: "qwen/qwen3.5-flash-02-23", - name: "Qwen: Qwen3.5-Flash", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-25", - last_updated: "2026-02-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.065, output: 0.26 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3.6-plus": { - id: "qwen/qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.325, output: 1.95, cache_read: 0.0325, cache_write: 0.40625 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3-max": { - id: "qwen/qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6, cache_read: 0.156, cache_write: 0.975 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen/qwen3-coder:exacto": { - id: "qwen/qwen3-coder:exacto", - name: "Qwen3 Coder (exacto)", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.38, output: 1.53 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-30b-a3b-instruct-2507": { - id: "qwen/qwen3-30b-a3b-instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262000, output: 262000 }, - }, - "qwen/qwen-3.6-27b": { - id: "qwen/qwen-3.6-27b", - name: "Qwen3.6 27B", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.195, output: 1.56 }, - limit: { context: 262144, output: 81920 }, - }, - "qwen/qwen3-235b-a22b-thinking-2507": { - id: "qwen/qwen3-235b-a22b-thinking-2507", - name: "Qwen3 235B A22B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.078, output: 0.312 }, - limit: { context: 262144, output: 81920 }, - }, - "qwen/qwen3-next-80b-a3b-thinking": { - id: "qwen/qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-11", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3-30b-a3b-thinking-2507": { - id: "qwen/qwen3-30b-a3b-thinking-2507", - name: "Qwen3 30B A3B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262000, output: 262000 }, - }, - "qwen/qwen3-coder-flash": { - id: "qwen/qwen3-coder-flash", - name: "Qwen3 Coder Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5, cache_read: 0.039, cache_write: 0.24375 }, - limit: { context: 128000, output: 66536 }, - }, - "qwen/qwen3-next-80b-a3b-instruct": { - id: "qwen/qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-11", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen-2.5-coder-32b-instruct": { - id: "qwen/qwen-2.5-coder-32b-instruct", - name: "Qwen2.5 Coder 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-11-11", - last_updated: "2024-11-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "qwen/qwen3-coder-30b-a3b-instruct": { - id: "qwen/qwen3-coder-30b-a3b-instruct", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.27 }, - limit: { context: 160000, output: 65536 }, - }, - "qwen/qwen3-coder": { - id: "qwen/qwen3-coder", - name: "Qwen3 Coder", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 262144, output: 66536 }, - }, - "qwen/qwen3.5-plus-02-15": { - id: "qwen/qwen3.5-plus-02-15", - name: "Qwen3.5 Plus 2026-02-15", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3-235b-a22b-07-25": { - id: "qwen/qwen3-235b-a22b-07-25", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-28", - last_updated: "2025-07-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.85 }, - limit: { context: 262144, output: 131072 }, - }, - "google/gemini-2.5-pro-preview-05-06": { - id: "google/gemini-2.5-pro-preview-05-06", - name: "Gemini 2.5 Pro Preview 05-06", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-05-06", - last_updated: "2025-05-06", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3.1-pro-preview-customtools": { - id: "google/gemini-3.1-pro-preview-customtools", - name: "Gemini 3.1 Pro Preview Custom Tools", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, reasoning: 12, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-3-4b-it:free": { - id: "google/gemma-3-4b-it:free", - name: "Gemma 3 4B (free)", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "google/gemini-2.5-flash-lite-preview-09-2025": { - id: "google/gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview 09-25", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.0-flash-001": { - id: "google/gemini-2.0-flash-001", - name: "Gemini 2.0 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 8192 }, - }, - "google/gemma-3n-e4b-it": { - id: "google/gemma-3n-e4b-it", - name: "Gemma 3n 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04 }, - limit: { context: 32768, output: 32768 }, - }, - "google/gemini-3.1-flash-lite-preview": { - id: "google/gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video", "pdf", "audio"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.25, - output: 1.5, - reasoning: 1.5, - cache_read: 0.025, - cache_write: 0.083, - input_audio: 0.5, - output_audio: 0.5, - }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-3n-e4b-it:free": { - id: "google/gemma-3n-e4b-it:free", - name: "Gemma 3n 4B (free)", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "google/gemini-3.1-pro-preview": { - id: "google/gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, reasoning: 12, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-pro-preview": { - id: "google/gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12 }, - limit: { context: 1050000, output: 66000 }, - }, - "google/gemma-3n-e2b-it:free": { - id: "google/gemma-3n-e2b-it:free", - name: "Gemma 3n 2B (free)", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "google/gemma-2-9b-it": { - id: "google/gemma-2-9b-it", - name: "Gemma 2 9B", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-28", - last_updated: "2024-06-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.09 }, - limit: { context: 8192, output: 8192 }, - }, - "google/gemma-4-31b-it": { - id: "google/gemma-4-31b-it", - name: "Gemma 4 31B", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.4 }, - limit: { context: 262144, output: 262144 }, - }, - "google/gemini-2.5-pro-preview-06-05": { - id: "google/gemini-2.5-pro-preview-06-05", - name: "Gemini 2.5 Pro Preview 06-05", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-3-12b-it": { - id: "google/gemma-3-12b-it", - name: "Gemma 3 12B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.1 }, - limit: { context: 131072, output: 131072 }, - }, - "google/gemma-3-27b-it:free": { - id: "google/gemma-3-27b-it:free", - name: "Gemma 3 27B (free)", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-07-17", - last_updated: "2025-07-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3.1-flash-image-preview": { - id: "google/gemini-3.1-flash-image-preview", - name: "Gemini 3.1 Flash Image Preview (Nano Banana 2)", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 65536, output: 65536 }, - }, - "google/gemma-4-31b-it:free": { - id: "google/gemma-4-31b-it:free", - name: "Gemma 4 31B (free)", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "google/gemma-3-12b-it:free": { - id: "google/gemma-3-12b-it:free", - name: "Gemma 3 12B (free)", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "google/gemma-3-4b-it": { - id: "google/gemma-3-4b-it", - name: "Gemma 3 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01703, output: 0.06815 }, - limit: { context: 96000, output: 96000 }, - }, - "google/gemini-2.5-flash-preview-09-2025": { - id: "google/gemini-2.5-flash-preview-09-2025", - name: "Gemini 2.5 Flash Preview 09-25", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.031 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.15 }, - limit: { context: 96000, output: 96000 }, - }, - "google/gemma-4-26b-a4b-it": { - id: "google/gemma-4-26b-a4b-it", - name: "Gemma 4 26B A4B", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-03", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4 }, - limit: { context: 262144, output: 262144 }, - }, - "google/gemma-4-26b-a4b-it:free": { - id: "google/gemma-4-26b-a4b-it:free", - name: "Gemma 4 26B A4B (free)", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-03", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "google/gemini-2.5-flash-lite": { - id: "google/gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 Instruct 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 16384 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-0905:exacto": { - id: "moonshotai/kimi-k2-0905:exacto", - name: "Kimi K2 Instruct 0905 (exacto)", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 16384 }, - }, - "moonshotai/kimi-k2": { - id: "moonshotai/kimi-k2", - name: "Kimi K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 131072, output: 32768 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3.7-sonnet": { - id: "anthropic/claude-3.7-sonnet", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-01", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 128000 }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.7": { - id: "anthropic/claude-opus-4.7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4.5": { - id: "anthropic/claude-sonnet-4.5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 64000 }, - }, - "anthropic/claude-opus-4.5": { - id: "anthropic/claude-opus-4.5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-30", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "deepseek/deepseek-v4-flash": { - id: "deepseek/deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1048576, output: 393216 }, - }, - "deepseek/deepseek-v4-pro": { - id: "deepseek/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1048576, output: 393216 }, - }, - "x-ai/grok-4.3": { - id: "x-ai/grok-4.3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-05-01", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 2.5, - cache_read: 0.2, - context_over_200k: { input: 2.5, output: 5, cache_read: 0.4 }, - }, - limit: { context: 1000000, output: 1000000 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5.5-pro": { - id: "openai/gpt-5.5-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3.5-haiku": { - id: "anthropic/claude-3.5-haiku", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "xiaomi/mimo-v2.5-pro": { - id: "xiaomi/mimo-v2.5-pro", - name: "Xiaomi: MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-omni": { - id: "xiaomi/mimo-v2-omni", - name: "Xiaomi: MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 262144, output: 131072 }, - }, - "xiaomi/mimo-v2.5": { - id: "xiaomi/mimo-v2.5", - name: "Xiaomi: MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-pro": { - id: "xiaomi/mimo-v2-pro", - name: "Xiaomi: MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "Xiaomi: MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - "fireworks-ai": { - id: "fireworks-ai", - env: ["FIREWORKS_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.fireworks.ai/inference/v1/", - name: "Fireworks AI", - doc: "https://fireworks.ai/docs/", - models: { - "accounts/fireworks/models/glm-5p1": { - id: "accounts/fireworks/models/glm-5p1", - name: "GLM 5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202800, output: 131072 }, - }, - "accounts/fireworks/models/deepseek-v3p2": { - id: "accounts/fireworks/models/deepseek-v3p2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-09", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68, cache_read: 0.28 }, - limit: { context: 160000, output: 160000 }, - }, - "accounts/fireworks/models/minimax-m2p5": { - id: "accounts/fireworks/models/minimax-m2p5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 196608, output: 196608 }, - }, - "accounts/fireworks/models/glm-4p5-air": { - id: "accounts/fireworks/models/glm-4p5-air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.88 }, - limit: { context: 131072, output: 131072 }, - }, - "accounts/fireworks/models/glm-5": { - id: "accounts/fireworks/models/glm-5", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.5 }, - limit: { context: 202752, output: 131072 }, - }, - "accounts/fireworks/models/deepseek-v3p1": { - id: "accounts/fireworks/models/deepseek-v3p1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68 }, - limit: { context: 163840, output: 163840 }, - }, - "accounts/fireworks/models/kimi-k2p6": { - id: "accounts/fireworks/models/kimi-k2p6", - name: "Kimi K2.6", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262000, output: 262000 }, - }, - "accounts/fireworks/models/kimi-k2-instruct": { - id: "accounts/fireworks/models/kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 128000, output: 16384 }, - }, - "accounts/fireworks/models/qwen3p6-plus": { - id: "accounts/fireworks/models/qwen3p6-plus", - name: "Qwen 3.6 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-04", - last_updated: "2026-04-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.1 }, - limit: { context: 128000, output: 8192 }, - }, - "accounts/fireworks/models/minimax-m2p1": { - id: "accounts/fireworks/models/minimax-m2p1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 200000, output: 200000 }, - }, - "accounts/fireworks/models/minimax-m2p7": { - id: "accounts/fireworks/models/minimax-m2p7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-12", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 196608, output: 196608 }, - }, - "accounts/fireworks/models/glm-4p7": { - id: "accounts/fireworks/models/glm-4p7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.3 }, - limit: { context: 198000, output: 198000 }, - }, - "accounts/fireworks/models/glm-4p5": { - id: "accounts/fireworks/models/glm-4p5", - name: "GLM 4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 131072, output: 131072 }, - }, - "accounts/fireworks/models/kimi-k2p5": { - id: "accounts/fireworks/models/kimi-k2p5", - name: "Kimi K2.5", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 256000, output: 256000 }, - }, - "accounts/fireworks/models/gpt-oss-20b": { - id: "accounts/fireworks/models/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.2 }, - limit: { context: 131072, output: 32768 }, - }, - "accounts/fireworks/models/gpt-oss-120b": { - id: "accounts/fireworks/models/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 32768 }, - }, - "accounts/fireworks/models/kimi-k2-thinking": { - id: "accounts/fireworks/models/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.3 }, - limit: { context: 256000, output: 256000 }, - }, - "accounts/fireworks/routers/kimi-k2p5-turbo": { - id: "accounts/fireworks/routers/kimi-k2p5-turbo", - name: "Kimi K2.5 Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 256000, output: 256000 }, - }, - "accounts/fireworks/models/deepseek-v4-pro": { - id: "accounts/fireworks/models/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.15 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - "kimi-for-coding": { - id: "kimi-for-coding", - env: ["KIMI_API_KEY"], - npm: "@ai-sdk/anthropic", - api: "https://api.kimi.com/coding/v1", - name: "Kimi For Coding", - doc: "https://www.kimi.com/coding/docs/en/third-party-agents.html", - models: { - k2p6: { - id: "k2p6", - name: "Kimi K2.6", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04", - last_updated: "2026-04", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - k2p5: { - id: "k2p5", - name: "Kimi K2.5", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11", - last_updated: "2025-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - }, - }, - moark: { - id: "moark", - env: ["MOARK_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://moark.com/v1", - name: "Moark", - doc: "https://moark.com/docs/openapi/v1#tag/%E6%96%87%E6%9C%AC%E7%94%9F%E6%88%90", - models: { - "GLM-4.7": { - id: "GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3.5, output: 14 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.1, output: 8.4 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - "opencode-go": { - id: "opencode-go", - env: ["OPENCODE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://opencode.ai/zen/go/v1", - name: "OpenCode Go", - doc: "https://opencode.ai/docs/zen", - models: { - "minimax-m2.7": { - id: "minimax-m2.7", - name: "MiniMax M2.7", - family: "minimax-m2.7", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-k2.5", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 65536 }, - }, - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo V2.5 Pro", - family: "mimo-v2.5-pro", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 128000 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202752, output: 32768 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo V2 Omni", - family: "mimo-v2-omni", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 262144, output: 128000 }, - status: "deprecated", - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo V2.5", - family: "mimo-v2.5", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen3.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05, cache_write: 0.625 }, - limit: { context: 262144, output: 65536 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202752, output: 32768 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.0028 }, - limit: { context: 1000000, output: 384000 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 65536 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.0145 }, - limit: { context: 1000000, output: 384000 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax-m2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 65536 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo V2 Pro", - family: "mimo-v2-pro", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 128000 }, - status: "deprecated", - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen3.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.2, cache_read: 0.02, cache_write: 0.25 }, - limit: { context: 262144, output: 65536 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - }, - }, - "io-net": { - id: "io-net", - env: ["IOINTELLIGENCE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.intelligence.io.solutions/api/v1", - name: "IO.NET", - doc: "https://io.net/docs/guides/intelligence/io-intelligence", - models: { - "Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar": { - id: "Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar", - name: "Qwen 3 Coder 480B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.95, cache_read: 0.11, cache_write: 0.44 }, - limit: { context: 106000, output: 4096 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Instruct": { - id: "Qwen/Qwen3-Next-80B-A3B-Instruct", - name: "Qwen 3 Next 80B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-10", - last_updated: "2025-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.8, cache_read: 0.05, cache_write: 0.2 }, - limit: { context: 262144, output: 4096 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen 3 235B Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.6, cache_read: 0.055, cache_write: 0.22 }, - limit: { context: 262144, output: 4096 }, - }, - "Qwen/Qwen2.5-VL-32B-Instruct": { - id: "Qwen/Qwen2.5-VL-32B-Instruct", - name: "Qwen 2.5 VL 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22, cache_read: 0.025, cache_write: 0.1 }, - limit: { context: 32000, output: 4096 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-11-15", - last_updated: "2024-11-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.75, cache_read: 0.2, cache_write: 0.8 }, - limit: { context: 200000, output: 4096 }, - }, - "mistralai/Magistral-Small-2506": { - id: "mistralai/Magistral-Small-2506", - name: "Magistral Small 2506", - family: "magistral-small", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5, cache_read: 0.25, cache_write: 1 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/Mistral-Large-Instruct-2411": { - id: "mistralai/Mistral-Large-Instruct-2411", - name: "Mistral Large Instruct 2411", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 1, cache_write: 4 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/Mistral-Nemo-Instruct-2407": { - id: "mistralai/Mistral-Nemo-Instruct-2407", - name: "Mistral Nemo Instruct 2407", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-05", - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04, cache_read: 0.01, cache_write: 0.04 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/Devstral-Small-2505": { - id: "mistralai/Devstral-Small-2505", - name: "Devstral Small 2505", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-05-01", - last_updated: "2025-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.22, cache_read: 0.025, cache_write: 0.1 }, - limit: { context: 128000, output: 4096 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.38, cache_read: 0.065, cache_write: 0.26 }, - limit: { context: 128000, output: 4096 }, - }, - "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": { - id: "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", - name: "Llama 4 Maverick 17B 128E Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6, cache_read: 0.075, cache_write: 0.3 }, - limit: { context: 430000, output: 4096 }, - }, - "meta-llama/Llama-3.2-90B-Vision-Instruct": { - id: "meta-llama/Llama-3.2-90B-Vision-Instruct", - name: "Llama 3.2 90B Vision Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 0.4, cache_read: 0.175, cache_write: 0.7 }, - limit: { context: 16000, output: 4096 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 8.75, cache_read: 1, cache_write: 4 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT-OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.14, cache_read: 0.015, cache_write: 0.06 }, - limit: { context: 64000, output: 4096 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT-OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.4, cache_read: 0.02, cache_write: 0.08 }, - limit: { context: 131072, output: 4096 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.55, output: 2.25, cache_read: 0.275, cache_write: 1.1 }, - limit: { context: 32768, output: 4096 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-09-05", - last_updated: "2024-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39, output: 1.9, cache_read: 0.195, cache_write: 0.78 }, - limit: { context: 32768, output: 4096 }, - }, - }, - }, - "alibaba-cn": { - id: "alibaba-cn", - env: ["DASHSCOPE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://dashscope.aliyuncs.com/compatible-mode/v1", - name: "Alibaba (China)", - doc: "https://www.alibabacloud.com/help/en/model-studio/models", - models: { - "qwen3-235b-a22b": { - id: "qwen3-235b-a22b", - name: "Qwen3 235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 1.147, reasoning: 2.868 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen-plus-character": { - id: "qwen-plus-character", - name: "Qwen Plus Character", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.115, output: 0.287 }, - limit: { context: 32768, output: 4096 }, - }, - "qwen2-5-math-7b-instruct": { - id: "qwen2-5-math-7b-instruct", - name: "Qwen2.5-Math 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 0.287 }, - limit: { context: 4096, output: 3072 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Moonshot Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: false, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.574, output: 2.411 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen-doc-turbo": { - id: "qwen-doc-turbo", - name: "Qwen Doc Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.087, output: 0.144 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-vl-ocr": { - id: "qwen-vl-ocr", - name: "Qwen-VL OCR", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2024-10-28", - last_updated: "2025-04-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.717, output: 0.717 }, - limit: { context: 34096, output: 4096 }, - }, - "qwen-omni-turbo-realtime": { - id: "qwen-omni-turbo-realtime", - name: "Qwen-Omni Turbo Realtime", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-05-08", - last_updated: "2025-05-08", - modalities: { input: ["text", "image", "audio"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.23, output: 0.918, input_audio: 3.584, output_audio: 7.168 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen3-8b": { - id: "qwen3-8b", - name: "Qwen3 8B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.072, output: 0.287, reasoning: 0.717 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen3.5 397B-A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.43, output: 2.58, reasoning: 2.58 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-math-turbo": { - id: "qwen-math-turbo", - name: "Qwen Math Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 4096, output: 3072 }, - }, - "qwq-plus": { - id: "qwq-plus", - name: "QwQ Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.23, output: 0.574 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-vl-plus": { - id: "qwen-vl-plus", - name: "Qwen-VL Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-08-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.115, output: 0.287 }, - limit: { context: 131072, output: 8192 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.86, output: 3.15 }, - limit: { context: 202752, output: 16384 }, - }, - "deepseek-r1-distill-llama-70b": { - id: "deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 1.147, reasoning: 2.868 }, - limit: { context: 131072, output: 16384 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen-max": { - id: "qwen-max", - name: "Qwen Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-03", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.345, output: 1.377 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-plus": { - id: "qwen-plus", - name: "Qwen Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.115, output: 0.287, reasoning: 1.147 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen-omni-turbo": { - id: "qwen-omni-turbo", - name: "Qwen-Omni Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01-19", - last_updated: "2025-03-26", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.058, output: 0.23, input_audio: 3.584, output_audio: 7.168 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen-flash": { - id: "qwen-flash", - name: "Qwen Flash", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.022, output: 0.216 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen2-5-vl-7b-instruct": { - id: "qwen2-5-vl-7b-instruct", - name: "Qwen2.5-VL 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 0.717 }, - limit: { context: 131072, output: 8192 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.574, output: 2.294 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen3.5-flash": { - id: "qwen3.5-flash", - name: "Qwen3.5 Flash", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-23", - last_updated: "2026-02-23", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.172, output: 1.72, reasoning: 1.72 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.276, output: 1.651, cache_read: 0.028, cache_write: 0.344 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.861, output: 3.441 }, - limit: { context: 262144, output: 65536 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-14", - last_updated: "2026-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.87, output: 3.48, cache_read: 0.17 }, - limit: { context: 202752, output: 128000 }, - }, - "qwen3-omni-flash": { - id: "qwen3-omni-flash", - name: "Qwen3-Omni Flash", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.058, output: 0.23, input_audio: 3.584, output_audio: 7.168 }, - limit: { context: 65536, output: 16384 }, - }, - "deepseek-v3-1": { - id: "deepseek-v3-1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.574, output: 1.721 }, - limit: { context: 131072, output: 65536 }, - }, - "qwen2-5-72b-instruct": { - id: "qwen2-5-72b-instruct", - name: "Qwen2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.574, output: 1.721 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-vl-235b-a22b": { - id: "qwen3-vl-235b-a22b", - name: "Qwen3-VL 235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.286705, output: 1.14682, reasoning: 2.867051 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen-math-plus": { - id: "qwen-math-plus", - name: "Qwen Math Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-08-16", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.574, output: 1.721 }, - limit: { context: 4096, output: 3072 }, - }, - "qwen2-5-coder-32b-instruct": { - id: "qwen2-5-coder-32b-instruct", - name: "Qwen2.5-Coder 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-11", - last_updated: "2024-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-asr-flash": { - id: "qwen3-asr-flash", - name: "Qwen3-ASR Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-04", - release_date: "2025-09-08", - last_updated: "2025-09-08", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.032, output: 0.032 }, - limit: { context: 53248, output: 4096 }, - }, - "qwen-deep-research": { - id: "qwen-deep-research", - name: "Qwen Deep Research", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 7.742, output: 23.367 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen3-next-80b-a3b-thinking": { - id: "qwen3-next-80b-a3b-thinking", - name: "Qwen3-Next 80B-A3B (Thinking)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 1.434 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen-mt-plus": { - id: "qwen-mt-plus", - name: "Qwen-MT Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.259, output: 0.775 }, - limit: { context: 16384, output: 8192 }, - }, - "deepseek-r1-distill-qwen-32b": { - id: "deepseek-r1-distill-qwen-32b", - name: "DeepSeek R1 Distill Qwen 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen-vl-max": { - id: "qwen-vl-max", - name: "Qwen-VL Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-08", - last_updated: "2025-08-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.23, output: 0.574 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-coder-flash": { - id: "qwen3-coder-flash", - name: "Qwen3 Coder Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.144, output: 0.574 }, - limit: { context: 1000000, output: 65536 }, - }, - "deepseek-r1-distill-qwen-7b": { - id: "deepseek-r1-distill-qwen-7b", - name: "DeepSeek R1 Distill Qwen 7B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.072, output: 0.144 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen2-5-7b-instruct": { - id: "qwen2-5-7b-instruct", - name: "Qwen2.5 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.072, output: 0.144 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen2-5-14b-instruct": { - id: "qwen2-5-14b-instruct", - name: "Qwen2.5 14B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 0.431 }, - limit: { context: 131072, output: 8192 }, - }, - "tongyi-intent-detect-v3": { - id: "tongyi-intent-detect-v3", - name: "Tongyi Intent Detect V3", - family: "yi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.058, output: 0.144 }, - limit: { context: 8192, output: 1024 }, - }, - "qwq-32b": { - id: "qwq-32b", - name: "QwQ 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 131072, output: 8192 }, - }, - "moonshot-kimi-k2-instruct": { - id: "moonshot-kimi-k2-instruct", - name: "Moonshot Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.574, output: 2.294 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen2-5-32b-instruct": { - id: "qwen2-5-32b-instruct", - name: "Qwen2.5 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.287, output: 0.861 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-next-80b-a3b-instruct": { - id: "qwen3-next-80b-a3b-instruct", - name: "Qwen3-Next 80B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 0.574 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen3-omni-flash-realtime": { - id: "qwen3-omni-flash-realtime", - name: "Qwen3-Omni Flash Realtime", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image", "audio"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.23, output: 0.918, input_audio: 3.584, output_audio: 7.168 }, - limit: { context: 65536, output: 16384 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Moonshot Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: false, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.929, output: 3.858 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen3-vl-30b-a3b": { - id: "qwen3-vl-30b-a3b", - name: "Qwen3-VL 30B-A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.108, output: 0.431, reasoning: 1.076 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen3-vl-plus": { - id: "qwen3-vl-plus", - name: "Qwen3-VL Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.143353, output: 1.433525, reasoning: 4.300576 }, - limit: { context: 262144, output: 32768 }, - }, - "deepseek-v3-2-exp": { - id: "deepseek-v3-2-exp", - name: "DeepSeek V3.2 Exp", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.287, output: 0.431 }, - limit: { context: 131072, output: 65536 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "Qwen3-Coder 480B-A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.861, output: 3.441 }, - limit: { context: 262144, output: 65536 }, - }, - "deepseek-r1-distill-qwen-1-5b": { - id: "deepseek-r1-distill-qwen-1-5b", - name: "DeepSeek R1 Distill Qwen 1.5B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3-Coder 30B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.216, output: 0.861 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen2-5-coder-7b-instruct": { - id: "qwen2-5-coder-7b-instruct", - name: "Qwen2.5-Coder 7B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-11", - last_updated: "2024-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 0.287 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-turbo": { - id: "qwen-turbo", - name: "Qwen Turbo", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-11-01", - last_updated: "2025-07-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.044, output: 0.087, reasoning: 0.431 }, - limit: { context: 1000000, output: 16384 }, - }, - "qwen-mt-turbo": { - id: "qwen-mt-turbo", - name: "Qwen-MT Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.101, output: 0.28 }, - limit: { context: 16384, output: 8192 }, - }, - "qwen2-5-math-72b-instruct": { - id: "qwen2-5-math-72b-instruct", - name: "Qwen2.5-Math 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.574, output: 1.721 }, - limit: { context: 4096, output: 3072 }, - }, - "qwen3.6-max-preview": { - id: "qwen3.6-max-preview", - name: "Qwen3.6 Max Preview", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.32, output: 7.9, cache_read: 0.132 }, - limit: { context: 245800, output: 65536 }, - }, - "qwen2-5-omni-7b": { - id: "qwen2-5-omni-7b", - name: "Qwen2.5-Omni 7B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: true, - cost: { input: 0.087, output: 0.345, input_audio: 5.448 }, - limit: { context: 32768, output: 2048 }, - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.573, output: 3.44, reasoning: 3.44 }, - limit: { context: 1000000, output: 65536 }, - }, - "deepseek-r1-distill-qwen-14b": { - id: "deepseek-r1-distill-qwen-14b", - name: "DeepSeek R1 Distill Qwen 14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.144, output: 0.431 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen2-5-vl-72b-instruct": { - id: "qwen2-5-vl-72b-instruct", - name: "Qwen2.5-VL 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.294, output: 6.881 }, - limit: { context: 131072, output: 8192 }, - }, - "deepseek-v3": { - id: "deepseek-v3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.287, output: 1.147 }, - limit: { context: 65536, output: 8192 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.574, output: 2.294 }, - limit: { context: 131072, output: 16384 }, - }, - "qvq-max": { - id: "qvq-max", - name: "QVQ Max", - family: "qvq", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.147, output: 4.588 }, - limit: { context: 131072, output: 8192 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Moonshot Kimi K2 Thinking", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.574, output: 2.294 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen3-14b": { - id: "qwen3-14b", - name: "Qwen3 14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.144, output: 0.574, reasoning: 1.434 }, - limit: { context: 131072, output: 8192 }, - }, - "deepseek-r1-distill-llama-8b": { - id: "deepseek-r1-distill-llama-8b", - name: "DeepSeek R1 Distill Llama 8B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen-long": { - id: "qwen-long", - name: "Qwen Long", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.072, output: 0.287 }, - limit: { context: 10000000, output: 8192 }, - }, - "kimi/kimi-k2.5": { - id: "kimi/kimi-k2.5", - name: "kimi/kimi-k2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMax/MiniMax-M2.7": { - id: "MiniMax/MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "siliconflow/deepseek-v3-0324": { - id: "siliconflow/deepseek-v3-0324", - name: "siliconflow/deepseek-v3-0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-26", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 163840, output: 163840 }, - }, - "siliconflow/deepseek-v3.2": { - id: "siliconflow/deepseek-v3.2", - name: "siliconflow/deepseek-v3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.42 }, - limit: { context: 163840, output: 65536 }, - }, - "siliconflow/deepseek-r1-0528": { - id: "siliconflow/deepseek-r1-0528", - name: "siliconflow/deepseek-r1-0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.18 }, - limit: { context: 163840, output: 32768 }, - }, - "siliconflow/deepseek-v3.1-terminus": { - id: "siliconflow/deepseek-v3.1-terminus", - name: "siliconflow/deepseek-v3.1-terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 163840, output: 65536 }, - }, - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 5 }, - limit: { context: 1048576, output: 65536 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - firepass: { - id: "firepass", - env: ["FIREPASS_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.fireworks.ai/inference/v1/", - name: "Fireworks (Firepass)", - doc: "https://docs.fireworks.ai/firepass", - models: { - "accounts/fireworks/routers/kimi-k2p6-turbo": { - id: "accounts/fireworks/routers/kimi-k2p6-turbo", - name: "Kimi K2.6 Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262000, output: 262000 }, - }, - }, - }, - "minimax-cn-coding-plan": { - id: "minimax-cn-coding-plan", - env: ["MINIMAX_API_KEY"], - npm: "@ai-sdk/anthropic", - api: "https://api.minimaxi.com/anthropic/v1", - name: "MiniMax Coding Plan (minimaxi.com)", - doc: "https://platform.minimaxi.com/docs/coding-plan/intro", - models: { - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 196608, output: 128000 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7-highspeed": { - id: "MiniMax-M2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.5-highspeed": { - id: "MiniMax-M2.5-highspeed", - name: "MiniMax-M2.5-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - jiekou: { - id: "jiekou", - env: ["JIEKOU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.jiekou.ai/openai", - name: "Jiekou.AI", - doc: "https://docs.jiekou.ai/docs/support/quickstart?utm_source=github_models.dev", - models: { - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "gpt-5.1-codex-max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "grok-4-1-fast-reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.45 }, - limit: { context: 2000000, output: 2000000 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "claude-opus-4-5-20251101", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 4.5, output: 22.5 }, - limit: { context: 200000, output: 65536 }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "gemini-2.5-flash-lite-preview-09-2025", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.36 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.2-pro": { - id: "gpt-5.2-pro", - name: "gpt-5.2-pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 18.9, output: 151.2 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "gemini-3-flash-preview", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "gpt-5-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.225, output: 1.8 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "gpt-5-nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.045, output: 0.36 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "gemini-3-pro-preview", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 1.8, output: 10.8 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-preview-05-20": { - id: "gemini-2.5-flash-preview-05-20", - name: "gemini-2.5-flash-preview-05-20", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.135, output: 3.15 }, - limit: { context: 1048576, output: 200000 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "claude-sonnet-4-5-20250929", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.7, output: 13.5 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "gemini-2.5-pro", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 1048576, output: 65535 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "grok-4-1-fast-non-reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.45 }, - limit: { context: 2000000, output: 2000000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "gpt-5.2", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.575, output: 12.6 }, - limit: { context: 400000, output: 128000 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, output: 100000 }, - }, - "gemini-2.5-pro-preview-06-05": { - id: "gemini-2.5-pro-preview-06-05", - name: "gemini-2.5-pro-preview-06-05", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 1048576, output: 200000 }, - }, - "gemini-2.5-flash-lite-preview-06-17": { - id: "gemini-2.5-flash-lite-preview-06-17", - name: "gemini-2.5-flash-lite-preview-06-17", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "video", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.36 }, - limit: { context: 1048576, output: 65535 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "gpt-5.2-codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "gemini-2.5-flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 2.25 }, - limit: { context: 1048576, output: 65535 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "gpt-5.1-codex-mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.225, output: 1.8 }, - limit: { context: 400000, output: 128000 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "grok-code-fast-1", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 1.35 }, - limit: { context: 256000, output: 256000 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "gpt-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02", - last_updated: "2026-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "grok-4-fast-reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.45 }, - limit: { context: 2000000, output: 2000000 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 131072, output: 131072 }, - }, - "grok-4-0709": { - id: "grok-4-0709", - name: "grok-4-0709", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.7, output: 13.5 }, - limit: { context: 256000, output: 8192 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "gpt-5-codex", - family: "gpt-codex", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "claude-opus-4-1-20250805", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 13.5, output: 67.5 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "claude-haiku-4-5-20251001", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9, output: 4.5 }, - limit: { context: 20000, output: 64000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "claude-sonnet-4-20250514", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.7, output: 13.5 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "claude-opus-4-6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02", - last_updated: "2026-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 1000000, output: 128000 }, - }, - o3: { - id: "o3", - name: "o3", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 40 }, - limit: { context: 131072, output: 131072 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "gpt-5-pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 13.5, output: 108 }, - limit: { context: 400000, output: 272000 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "gemini-2.5-flash-lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.36 }, - limit: { context: 1048576, output: 65535 }, - }, - "gpt-5-chat-latest": { - id: "gpt-5-chat-latest", - name: "gpt-5-chat-latest", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "claude-opus-4-20250514", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 13.5, output: 67.5 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "gpt-5.1-codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.125, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "grok-4-fast-non-reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.45 }, - limit: { context: 2000000, output: 2000000 }, - }, - "deepseek/deepseek-v3-0324": { - id: "deepseek/deepseek-v3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.14 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-v3.1": { - id: "deepseek/deepseek-v3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 163840, output: 32768 }, - }, - "deepseek/deepseek-r1-0528": { - id: "deepseek/deepseek-r1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5 }, - limit: { context: 163840, output: 32768 }, - }, - "zai-org/glm-4.7": { - id: "zai-org/glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/glm-4.5": { - id: "zai-org/glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 131072, output: 98304 }, - }, - "zai-org/glm-4.5v": { - id: "zai-org/glm-4.5v", - name: "GLM 4.5V", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 65536, output: 16384 }, - }, - "zai-org/glm-4.7-flash": { - id: "zai-org/glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4 }, - limit: { context: 200000, output: 128000 }, - }, - "minimaxai/minimax-m1-80k": { - id: "minimaxai/minimax-m1-80k", - name: "MiniMax M1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 1000000, output: 40000 }, - }, - "xiaomimimo/mimo-v2-flash": { - id: "xiaomimimo/mimo-v2-flash", - name: "XiaomiMiMo/MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "baidu/ernie-4.5-vl-424b-a47b": { - id: "baidu/ernie-4.5-vl-424b-a47b", - name: "ERNIE 4.5 VL 424B A47B", - family: "ernie", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.42, output: 1.25 }, - limit: { context: 123000, output: 16000 }, - }, - "baidu/ernie-4.5-300b-a47b-paddle": { - id: "baidu/ernie-4.5-300b-a47b-paddle", - name: "ERNIE 4.5 300B A47B", - family: "ernie", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 123000, output: 12000 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "Minimax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen/qwen3-235b-a22b-instruct-2507": { - id: "qwen/qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.8 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen/qwen3-32b-fp8": { - id: "qwen/qwen3-32b-fp8", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.45 }, - limit: { context: 40960, output: 20000 }, - }, - "qwen/qwen3-235b-a22b-thinking-2507": { - id: "qwen/qwen3-235b-a22b-thinking-2507", - name: "Qwen3 235B A22b Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 3 }, - limit: { context: 131072, output: 131072 }, - }, - "qwen/qwen3-next-80b-a3b-thinking": { - id: "qwen/qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 65536, output: 65536 }, - }, - "qwen/qwen3-next-80b-a3b-instruct": { - id: "qwen/qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 65536, output: 65536 }, - }, - "qwen/qwen3-30b-a3b-fp8": { - id: "qwen/qwen3-30b-a3b-fp8", - name: "Qwen3 30B A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.45 }, - limit: { context: 40960, output: 20000 }, - }, - "qwen/qwen3-coder-next": { - id: "qwen/qwen3-coder-next", - name: "qwen/qwen3-coder-next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02", - last_updated: "2026-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-coder-480b-a35b-instruct": { - id: "qwen/qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 1.2 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-235b-a22b-fp8": { - id: "qwen/qwen3-235b-a22b-fp8", - name: "Qwen3 235B A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 40960, output: 20000 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-instruct": { - id: "moonshotai/kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.57, output: 2.3 }, - limit: { context: 131072, output: 131072 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - bailing: { - id: "bailing", - env: ["BAILING_API_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.tbox.cn/api/llm/v1/chat/completions", - name: "Bailing", - doc: "https://alipaytbox.yuque.com/sxs0ba/ling/intro", - models: { - "Ring-1T": { - id: "Ring-1T", - name: "Ring-1T", - family: "ring", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-10", - last_updated: "2025-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.57, output: 2.29 }, - limit: { context: 128000, output: 32000 }, - }, - "Ling-1T": { - id: "Ling-1T", - name: "Ling-1T", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-10", - last_updated: "2025-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.57, output: 2.29 }, - limit: { context: 128000, output: 32000 }, - }, - }, - }, - iflowcn: { - id: "iflowcn", - env: ["IFLOW_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://apis.iflow.cn/v1", - name: "iFlow", - doc: "https://platform.iflow.cn/en/docs", - models: { - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3-Coder-Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3-32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32000 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32000 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3-Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 32000 }, - }, - "qwen3-235b-a22b-instruct": { - id: "qwen3-235b-a22b-instruct", - name: "Qwen3-235B-A22B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "qwen3-235b-a22b-thinking-2507": { - id: "qwen3-235b-a22b-thinking-2507", - name: "Qwen3-235B-A22B-Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "kimi-k2-0905": { - id: "kimi-k2-0905", - name: "Kimi-K2-0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2025-11-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 128000 }, - }, - "qwen3-vl-plus": { - id: "qwen3-vl-plus", - name: "Qwen3-VL-Plus", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 32000 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek-V3.2-Exp", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 64000 }, - }, - "qwen3-235b": { - id: "qwen3-235b", - name: "Qwen3-235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32000 }, - }, - "kimi-k2": { - id: "kimi-k2", - name: "Kimi-K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 64000 }, - }, - "qwen3-max-preview": { - id: "qwen3-max-preview", - name: "Qwen3-Max-Preview", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 32000 }, - }, - "deepseek-v3": { - id: "deepseek-v3", - name: "DeepSeek-V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-26", - last_updated: "2024-12-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32000 }, - }, - }, - }, - v0: { - id: "v0", - env: ["V0_API_KEY"], - npm: "@ai-sdk/vercel", - name: "v0", - doc: "https://sdk.vercel.ai/providers/ai-sdk-providers/vercel", - models: { - "v0-1.5-lg": { - id: "v0-1.5-lg", - name: "v0-1.5-lg", - family: "v0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-09", - last_updated: "2025-06-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75 }, - limit: { context: 512000, output: 32000 }, - }, - "v0-1.0-md": { - id: "v0-1.0-md", - name: "v0-1.0-md", - family: "v0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, output: 32000 }, - }, - "v0-1.5-md": { - id: "v0-1.5-md", - name: "v0-1.5-md", - family: "v0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-09", - last_updated: "2025-06-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, output: 32000 }, - }, - }, - }, - huggingface: { - id: "huggingface", - env: ["HF_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://router.huggingface.co/v1", - name: "Hugging Face", - doc: "https://huggingface.co/docs/inference-providers", - models: { - "Qwen/Qwen3.5-397B-A17B": { - id: "Qwen/Qwen3.5-397B-A17B", - name: "Qwen3.5-397B-A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 32768 }, - }, - "Qwen/Qwen3-Coder-Next": { - id: "Qwen/Qwen3-Coder-Next", - name: "Qwen3-Coder-Next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-03", - last_updated: "2026-02-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Instruct": { - id: "Qwen/Qwen3-Next-80B-A3B-Instruct", - name: "Qwen3-Next-80B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-11", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1 }, - limit: { context: 262144, output: 66536 }, - }, - "Qwen/Qwen3-Embedding-8B": { - id: "Qwen/Qwen3-Embedding-8B", - name: "Qwen 3 Embedding 8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0 }, - limit: { context: 32000, output: 4096 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3-235B-A22B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 3 }, - limit: { context: 262144, output: 131072 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Thinking": { - id: "Qwen/Qwen3-Next-80B-A3B-Thinking", - name: "Qwen3-Next-80B-A3B-Thinking", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-11", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2 }, - limit: { context: 262144, output: 131072 }, - }, - "Qwen/Qwen3-Embedding-4B": { - id: "Qwen/Qwen3-Embedding-4B", - name: "Qwen 3 Embedding 4B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0 }, - limit: { context: 32000, output: 2048 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen3-Coder-480B-A35B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 2 }, - limit: { context: 262144, output: 66536 }, - }, - "zai-org/GLM-4.7-Flash": { - id: "zai-org/GLM-4.7-Flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 128000 }, - }, - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-03", - last_updated: "2026-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202752, output: 131072 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202752, output: 131072 }, - }, - "XiaomiMiMo/MiMo-V2-Flash": { - id: "XiaomiMiMo/MiMo-V2-Flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 262144, output: 4096 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek-R1-0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 5 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 0.4 }, - limit: { context: 163840, output: 65536 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "Kimi-K2-Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "Kimi-K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2-Instruct": { - id: "moonshotai/Kimi-K2-Instruct", - name: "Kimi-K2-Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-14", - last_updated: "2025-07-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 131072, output: 16384 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi-K2-Instruct-0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-04", - last_updated: "2025-09-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 262144, output: 16384 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi-K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-01", - last_updated: "2026-01-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMaxAI/MiniMax-M2.7": { - id: "MiniMaxAI/MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMaxAI/MiniMax-M2.1": { - id: "MiniMaxAI/MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-10", - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "deepseek-ai/DeepSeek-V4-Pro": { - id: "deepseek-ai/DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1048576, output: 393216 }, - }, - }, - }, - zenmux: { - id: "zenmux", - env: ["ZENMUX_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://zenmux.ai/api/v1", - name: "ZenMux", - doc: "https://docs.zenmux.ai", - models: { - "deepseek/deepseek-chat": { - id: "deepseek/deepseek-chat", - name: "DeepSeek-V3.2 (Non-thinking Mode)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 0.42, cache_read: 0.03 }, - limit: { context: 128000, output: 64000 }, - }, - "deepseek/deepseek-v3.2-exp": { - id: "deepseek/deepseek-v3.2-exp", - name: "DeepSeek-V3.2-Exp", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.22, output: 0.33 }, - limit: { context: 163000, output: 64000 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "DeepSeek V3.2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-05", - last_updated: "2025-12-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 0.43 }, - limit: { context: 128000, output: 64000 }, - }, - "inclusionai/ring-1t": { - id: "inclusionai/ring-1t", - name: "Ring-1T", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-10-12", - last_updated: "2025-10-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 2.24, cache_read: 0.11 }, - limit: { context: 128000, output: 64000 }, - }, - "inclusionai/ling-1t": { - id: "inclusionai/ling-1t", - name: "Ling-1T", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-10-09", - last_updated: "2025-10-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 2.24, cache_read: 0.11 }, - limit: { context: 128000, output: 64000 }, - }, - "stepfun/step-3.5-flash-free": { - id: "stepfun/step-3.5-flash-free", - name: "Step 3.5 Flash (Free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "stepfun/step-3.5-flash": { - id: "stepfun/step-3.5-flash", - name: "Step 3.5 Flash", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 256000, output: 64000 }, - }, - "stepfun/step-3": { - id: "stepfun/step-3", - name: "Step-3", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.57 }, - limit: { context: 65536, output: 64000 }, - }, - "kuaishou/kat-coder-pro-v2": { - id: "kuaishou/kat-coder-pro-v2", - name: "KAT-Coder-Pro-V2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 256000, output: 80000 }, - }, - "x-ai/grok-4-fast": { - id: "x-ai/grok-4-fast", - name: "Grok 4 Fast", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 64000 }, - }, - "x-ai/grok-code-fast-1": { - id: "x-ai/grok-code-fast-1", - name: "Grok Code Fast 1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 64000 }, - }, - "x-ai/grok-4.1-fast-non-reasoning": { - id: "x-ai/grok-4.1-fast-non-reasoning", - name: "Grok 4.1 Fast Non Reasoning", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 64000 }, - }, - "x-ai/grok-4": { - id: "x-ai/grok-4", - name: "Grok 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "x-ai/grok-4.1-fast": { - id: "x-ai/grok-4.1-fast", - name: "Grok 4.1 Fast", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 64000 }, - }, - "x-ai/grok-4.2-fast": { - id: "x-ai/grok-4.2-fast", - name: "Grok 4.2 Fast", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 9 }, - limit: { context: 2000000, output: 30000 }, - }, - "x-ai/grok-4.2-fast-non-reasoning": { - id: "x-ai/grok-4.2-fast-non-reasoning", - name: "Grok 4.2 Fast Non Reasoning", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 9 }, - limit: { context: 2000000, output: 30000 }, - }, - "openai/gpt-5.3-chat": { - id: "openai/gpt-5.3-chat", - name: "GPT-5.3 Chat", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 128000, output: 16380 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT-5.2-Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT-5.3 Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-01-01", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["image", "text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.17 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.4-mini": { - id: "openai/gpt-5.4-mini", - name: "GPT-5.4 Mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5 }, - limit: { context: 400000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.1-chat": { - id: "openai/gpt-5.1-chat", - name: "GPT-5.1 Chat", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["pdf", "image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12 }, - limit: { context: 128000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.4-nano": { - id: "openai/gpt-5.4-nano", - name: "GPT-5.4 Nano", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25 }, - limit: { context: 400000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-01-01", - release_date: "2026-01-15", - last_updated: "2026-01-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.17 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT-5.1-Codex-Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["image", "text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "GPT-5.4 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 45, output: 225 }, - limit: { context: 1050000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5 Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.75, output: 18.75 }, - limit: { context: 1050000, output: 128000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12 }, - limit: { context: 400000, output: 64000 }, - provider: { npm: "@ai-sdk/openai", api: "https://zenmux.ai/api/v1" }, - }, - "z-ai/glm-4.7-flash-free": { - id: "z-ai/glm-4.7-flash-free", - name: "GLM 4.7 Flash (Free)", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-5v-turbo": { - id: "z-ai/glm-5v-turbo", - name: "GLM 5V Turbo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.726, output: 3.1946, cache_read: 0.1743 }, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/glm-4.7": { - id: "z-ai/glm-4.7", - name: "GLM 4.7", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 1.14, cache_read: 0.06 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-5": { - id: "z-ai/glm-5", - name: "GLM 5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 2.6, cache_read: 0.14 }, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/glm-4.7-flashx": { - id: "z-ai/glm-4.7-flashx", - name: "GLM 4.7 FlashX", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.42, cache_read: 0.01 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-4.6v-flash-free": { - id: "z-ai/glm-4.6v-flash-free", - name: "GLM 4.6V Flash (Free)", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-5.1": { - id: "z-ai/glm-5.1", - name: "GLM-5.1", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-03", - last_updated: "2026-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8781, output: 3.5126, cache_read: 0.1903 }, - limit: { context: 200000, output: 131072 }, - }, - "z-ai/glm-4.6v-flash": { - id: "z-ai/glm-4.6v-flash", - name: "GLM 4.6V FlashX", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.21, cache_read: 0.0043 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-4.5": { - id: "z-ai/glm-4.5", - name: "GLM 4.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 1.54, cache_read: 0.07 }, - limit: { context: 128000, output: 64000 }, - }, - "z-ai/glm-4.5-air": { - id: "z-ai/glm-4.5-air", - name: "GLM 4.5 Air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.11, output: 0.56, cache_read: 0.02 }, - limit: { context: 128000, output: 64000 }, - }, - "z-ai/glm-5-turbo": { - id: "z-ai/glm-5-turbo", - name: "GLM 5 Turbo", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.88, output: 3.48 }, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/glm-4.6": { - id: "z-ai/glm-4.6", - name: "GLM 4.6", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 1.54, cache_read: 0.07 }, - limit: { context: 200000, output: 64000 }, - }, - "z-ai/glm-4.6v": { - id: "z-ai/glm-4.6v", - name: "GLM 4.6V", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.42, cache_read: 0.03 }, - limit: { context: 200000, output: 64000 }, - }, - "volcengine/doubao-seed-2.0-code": { - id: "volcengine/doubao-seed-2.0-code", - name: "Doubao Seed 2.0 Code", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9, output: 4.48 }, - limit: { context: 256000, output: 32000 }, - }, - "volcengine/doubao-seed-code": { - id: "volcengine/doubao-seed-code", - name: "Doubao-Seed-Code", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-11", - last_updated: "2025-11-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.17, output: 1.12, cache_read: 0.03 }, - limit: { context: 256000, output: 64000 }, - }, - "volcengine/doubao-seed-2.0-mini": { - id: "volcengine/doubao-seed-2.0-mini", - name: "Doubao-Seed-2.0-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02-14", - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0.28, cache_read: 0.01, cache_write: 0.0024 }, - limit: { context: 256000, output: 64000 }, - }, - "volcengine/doubao-seed-2.0-lite": { - id: "volcengine/doubao-seed-2.0-lite", - name: "Doubao-Seed-2.0-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02-14", - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.51, cache_read: 0.02, cache_write: 0.0024 }, - limit: { context: 256000, output: 64000 }, - }, - "volcengine/doubao-seed-1.8": { - id: "volcengine/doubao-seed-1.8", - name: "Doubao-Seed-1.8", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.11, output: 0.28, cache_read: 0.02, cache_write: 0.0024 }, - limit: { context: 256000, output: 64000 }, - }, - "volcengine/doubao-seed-2.0-pro": { - id: "volcengine/doubao-seed-2.0-pro", - name: "Doubao-Seed-2.0-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02-14", - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 2.24, cache_read: 0.09, cache_write: 0.0024 }, - limit: { context: 256000, output: 64000 }, - }, - "baidu/ernie-5.0-thinking-preview": { - id: "baidu/ernie-5.0-thinking-preview", - name: "ERNIE 5.0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.84, output: 3.37 }, - limit: { context: 128000, output: 64000 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "MiniMax M2.7", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3055, output: 1.2219 }, - limit: { context: 204800, output: 131070 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "minimax/minimax-m2.7-highspeed": { - id: "minimax/minimax-m2.7-highspeed", - name: "MiniMax M2.7 highspeed", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.611, output: 2.4439 }, - limit: { context: 204800, output: 131070 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "MiniMax M2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.38 }, - limit: { context: 204000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "MiniMax M2.1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.38 }, - limit: { context: 204000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "minimax/minimax-m2.5-lightning": { - id: "minimax/minimax-m2.5-lightning", - name: "MiniMax M2.5 highspeed", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4.8, cache_read: 0.06, cache_write: 0.75 }, - limit: { context: 204800, output: 131072 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "qwen/qwen3-coder-plus": { - id: "qwen/qwen3-coder-plus", - name: "Qwen3-Coder-Plus", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 1000000, output: 64000 }, - }, - "qwen/qwen3.5-flash": { - id: "qwen/qwen3.5-flash", - name: "Qwen3.5 Flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1020000, output: 1020000 }, - }, - "qwen/qwen3.6-plus": { - id: "qwen/qwen3.6-plus", - name: "Qwen3.6-Plus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.5, - output: 3, - cache_read: 0.05, - cache_write: 0.625, - context_over_200k: { input: 2, output: 6, cache_read: 0.2, cache_write: 2.5 }, - }, - limit: { context: 1000000, output: 64000 }, - }, - "qwen/qwen3-max": { - id: "qwen/qwen3-max", - name: "Qwen3-Max-Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-01-23", - last_updated: "2026-01-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6 }, - limit: { context: 256000, output: 64000 }, - }, - "qwen/qwen3.5-plus": { - id: "qwen/qwen3.5-plus", - name: "Qwen3.5 Plus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-03-20", - last_updated: "2026-03-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4.8 }, - limit: { context: 1000000, output: 64000 }, - }, - "google/gemini-3.1-flash-lite-preview": { - id: "google/gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-03-20", - last_updated: "2025-03-20", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5 }, - limit: { context: 1050000, output: 65530 }, - }, - "google/gemini-3.1-pro-preview": { - id: "google/gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02-19", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "pdf", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, cache_write: 4.5 }, - limit: { context: 1048000, output: 64000 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "pdf", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05, cache_write: 1 }, - limit: { context: 1048000, output: 64000 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["pdf", "image", "text", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31, cache_write: 4.5 }, - limit: { context: 1048000, output: 64000 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["pdf", "image", "text", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.07, cache_write: 1 }, - limit: { context: 1048000, output: 64000 }, - }, - "google/gemini-2.5-flash-lite": { - id: "google/gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["pdf", "image", "text", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03, cache_write: 1 }, - limit: { context: 1048000, output: 64000 }, - }, - "sapiens-ai/agnes-1.5-lite": { - id: "sapiens-ai/agnes-1.5-lite", - name: "Agnes 1.5 Lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-26", - last_updated: "2026-03-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0.6 }, - limit: { context: 256000, output: 256000 }, - }, - "sapiens-ai/agnes-1.5-pro": { - id: "sapiens-ai/agnes-1.5-pro", - name: "Agnes 1.5 Pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-21", - last_updated: "2026-03-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.16, output: 0.8 }, - limit: { context: 256000, output: 256000 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: false, - knowledge: "2025-01-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.58, output: 3.02, cache_read: 0.1 }, - limit: { context: 262000, output: 64000 }, - }, - "moonshotai/kimi-k2-thinking-turbo": { - id: "moonshotai/kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.15, output: 8, cache_read: 0.15 }, - limit: { context: 262000, output: 64000 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 0905", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-04", - last_updated: "2025-09-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262000, output: 64000 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: false, - knowledge: "2025-01-01", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262140, output: 262140 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262000, output: 64000 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Claude Opus 4.1", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["image", "text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-3.7-sonnet": { - id: "anthropic/claude-3.7-sonnet", - name: "Claude 3.7 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Claude Opus 4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-opus-4.7": { - id: "anthropic/claude-opus-4.7", - name: "Claude Opus 4.7", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["image", "text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-sonnet-4.5": { - id: "anthropic/claude-sonnet-4.5", - name: "Claude Sonnet 4.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-opus-4.5": { - id: "anthropic/claude-opus-4.5", - name: "Claude Opus 4.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["pdf", "image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude Opus 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["image", "text", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-3.5-haiku": { - id: "anthropic/claude-3.5-haiku", - name: "Claude 3.5 Haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2024-11-04", - last_updated: "2024-11-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Claude Haiku 4.5", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Claude Sonnet 4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-18", - last_updated: "2026-02-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic", api: "https://zenmux.ai/api/anthropic/v1" }, - }, - "deepseek/deepseek-v4-flash": { - id: "deepseek/deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek/deepseek-v4-pro": { - id: "deepseek/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - }, - "tencent/hy3-preview": { - id: "tencent/hy3-preview", - name: "Hy3 preview", - family: "Hy", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.172, output: 0.572, cache_read: 0.058, cache_write: 0 }, - limit: { context: 256000, output: 64000 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - experimental: { - modes: { - fast: { - cost: { input: 12.5, output: 75, cache_read: 1.25 }, - provider: { body: { service_tier: "priority" } }, - }, - }, - }, - }, - "openai/gpt-5.5-pro": { - id: "openai/gpt-5.5-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "xiaomi/mimo-v2.5-pro": { - id: "xiaomi/mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-omni": { - id: "xiaomi/mimo-v2-omni", - name: "MiMo V2 Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 265000, output: 265000 }, - }, - "xiaomi/mimo-v2.5": { - id: "xiaomi/mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-pro": { - id: "xiaomi/mimo-v2-pro", - name: "MiMo V2 Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1000000, output: 256000 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - upstage: { - id: "upstage", - env: ["UPSTAGE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.upstage.ai/v1/solar", - name: "Upstage", - doc: "https://developers.upstage.ai/docs/apis/chat", - models: { - "solar-pro2": { - id: "solar-pro2", - name: "solar-pro2", - family: "solar-pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.25 }, - limit: { context: 65536, output: 8192 }, - }, - "solar-mini": { - id: "solar-mini", - name: "solar-mini", - family: "solar-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-06-12", - last_updated: "2025-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 32768, output: 4096 }, - }, - "solar-pro3": { - id: "solar-pro3", - name: "solar-pro3", - family: "solar-pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.25 }, - limit: { context: 131072, output: 8192 }, - }, - }, - }, - "novita-ai": { - id: "novita-ai", - env: ["NOVITA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.novita.ai/openai", - name: "NovitaAI", - doc: "https://novita.ai/docs/guides/introduction", - models: { - "deepseek/deepseek-r1-turbo": { - id: "deepseek/deepseek-r1-turbo", - name: "DeepSeek R1 (Turbo)\t", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5 }, - limit: { context: 64000, output: 16000 }, - }, - "deepseek/deepseek-v3-0324": { - id: "deepseek/deepseek-v3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1.12, cache_read: 0.135 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-ocr-2": { - id: "deepseek/deepseek-ocr-2", - name: "deepseek/deepseek-ocr-2", - attachment: true, - reasoning: false, - tool_call: false, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.03 }, - limit: { context: 8192, output: 8192 }, - }, - "deepseek/deepseek-ocr": { - id: "deepseek/deepseek-ocr", - name: "DeepSeek-OCR", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-10-24", - last_updated: "2025-10-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.03 }, - limit: { context: 8192, output: 8192 }, - }, - "deepseek/deepseek-r1-distill-llama-70b": { - id: "deepseek/deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill LLama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 0.8 }, - limit: { context: 8192, output: 8192 }, - }, - "deepseek/deepseek-prover-v2-671b": { - id: "deepseek/deepseek-prover-v2-671b", - name: "Deepseek Prover V2 671B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5 }, - limit: { context: 160000, output: 160000 }, - }, - "deepseek/deepseek-r1-0528-qwen3-8b": { - id: "deepseek/deepseek-r1-0528-qwen3-8b", - name: "DeepSeek R1 0528 Qwen3 8B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-05-29", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.09 }, - limit: { context: 128000, output: 32000 }, - }, - "deepseek/deepseek-r1-distill-qwen-32b": { - id: "deepseek/deepseek-r1-distill-qwen-32b", - name: "DeepSeek R1 Distill Qwen 32B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 64000, output: 32000 }, - }, - "deepseek/deepseek-v3.2-exp": { - id: "deepseek/deepseek-v3.2-exp", - name: "Deepseek V3.2 Exp", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v3.1": { - id: "deepseek/deepseek-v3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1, cache_read: 0.135 }, - limit: { context: 131072, output: 32768 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "Deepseek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.269, output: 0.4, cache_read: 0.1345 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v3-turbo": { - id: "deepseek/deepseek-v3-turbo", - name: "DeepSeek V3 (Turbo)\t", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.3 }, - limit: { context: 64000, output: 16000 }, - }, - "deepseek/deepseek-r1-distill-qwen-14b": { - id: "deepseek/deepseek-r1-distill-qwen-14b", - name: "DeepSeek R1 Distill Qwen 14B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 32768, output: 16384 }, - }, - "deepseek/deepseek-r1-0528": { - id: "deepseek/deepseek-r1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5, cache_read: 0.35 }, - limit: { context: 163840, output: 32768 }, - }, - "deepseek/deepseek-v3.1-terminus": { - id: "deepseek/deepseek-v3.1-terminus", - name: "Deepseek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1, cache_read: 0.135 }, - limit: { context: 131072, output: 32768 }, - }, - "inclusionai/ling-2.6-1t": { - id: "inclusionai/ling-2.6-1t", - name: "Ling-2.6-1T", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "paddlepaddle/paddleocr-vl": { - id: "paddlepaddle/paddleocr-vl", - name: "PaddleOCR-VL", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-22", - last_updated: "2025-10-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.02 }, - limit: { context: 16384, output: 16384 }, - }, - "nousresearch/hermes-2-pro-llama-3-8b": { - id: "nousresearch/hermes-2-pro-llama-3-8b", - name: "Hermes 2 Pro Llama 3 8B", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-06-27", - last_updated: "2024-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.14 }, - limit: { context: 8192, output: 8192 }, - }, - "zai-org/glm-4.7": { - id: "zai-org/glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/glm-5": { - id: "zai-org/glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202800, output: 131072 }, - }, - "zai-org/glm-5.1": { - id: "zai-org/glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/glm-4.5": { - id: "zai-org/glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11 }, - limit: { context: 131072, output: 98304 }, - }, - "zai-org/glm-4.5-air": { - id: "zai-org/glm-4.5-air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-10-13", - last_updated: "2025-10-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.85 }, - limit: { context: 131072, output: 98304 }, - }, - "zai-org/glm-4.5v": { - id: "zai-org/glm-4.5v", - name: "GLM 4.5V", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "video", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8, cache_read: 0.11 }, - limit: { context: 65536, output: 16384 }, - }, - "zai-org/glm-4.6": { - id: "zai-org/glm-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2, cache_read: 0.11 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/glm-4.6v": { - id: "zai-org/glm-4.6v", - name: "GLM 4.6V", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "video", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9, cache_read: 0.055 }, - limit: { context: 131072, output: 32768 }, - }, - "zai-org/glm-4.7-flash": { - id: "zai-org/glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4, cache_read: 0.01 }, - limit: { context: 200000, output: 128000 }, - }, - "zai-org/autoglm-phone-9b-multilingual": { - id: "zai-org/autoglm-phone-9b-multilingual", - name: "AutoGLM-Phone-9B-Multilingual", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-12-10", - last_updated: "2025-12-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.035, output: 0.138 }, - limit: { context: 65536, output: 65536 }, - }, - "mistralai/mistral-nemo": { - id: "mistralai/mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-07-30", - last_updated: "2024-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.17 }, - limit: { context: 60288, output: 16000 }, - }, - "baichuan/baichuan-m2-32b": { - id: "baichuan/baichuan-m2-32b", - name: "baichuan-m2-32b", - family: "baichuan", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2024-12", - release_date: "2025-08-13", - last_updated: "2025-08-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.07 }, - limit: { context: 131072, output: 131072 }, - }, - "meta-llama/llama-4-scout-17b-16e-instruct": { - id: "meta-llama/llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout Instruct", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-06", - last_updated: "2025-04-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.59 }, - limit: { context: 131072, output: 131072 }, - }, - "meta-llama/llama-3.3-70b-instruct": { - id: "meta-llama/llama-3.3-70b-instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-07", - last_updated: "2024-12-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.135, output: 0.4 }, - limit: { context: 131072, output: 120000 }, - }, - "meta-llama/llama-3.2-3b-instruct": { - id: "meta-llama/llama-3.2-3b-instruct", - name: "Llama 3.2 3B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.05 }, - limit: { context: 32768, output: 32000 }, - }, - "meta-llama/llama-3-8b-instruct": { - id: "meta-llama/llama-3-8b-instruct", - name: "Llama 3 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-25", - last_updated: "2024-04-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 8192, output: 8192 }, - }, - "meta-llama/llama-3.1-8b-instruct": { - id: "meta-llama/llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-07-24", - last_updated: "2024-07-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.05 }, - limit: { context: 16384, output: 16384 }, - }, - "meta-llama/llama-3-70b-instruct": { - id: "meta-llama/llama-3-70b-instruct", - name: "Llama3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-04-25", - last_updated: "2024-04-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.51, output: 0.74 }, - limit: { context: 8192, output: 8000 }, - }, - "meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { - id: "meta-llama/llama-4-maverick-17b-128e-instruct-fp8", - name: "Llama 4 Maverick Instruct", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-06", - last_updated: "2025-04-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.85 }, - limit: { context: 1048576, output: 8192 }, - }, - "gryphe/mythomax-l2-13b": { - id: "gryphe/mythomax-l2-13b", - name: "Mythomax L2 13B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-25", - last_updated: "2024-04-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.09 }, - limit: { context: 4096, output: 3200 }, - }, - "sao10k/l31-70b-euryale-v2.2": { - id: "sao10k/l31-70b-euryale-v2.2", - name: "L31 70B Euryale V2.2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.48, output: 1.48 }, - limit: { context: 8192, output: 8192 }, - }, - "sao10k/l3-70b-euryale-v2.1": { - id: "sao10k/l3-70b-euryale-v2.1", - name: "L3 70B Euryale V2.1\t", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-06-18", - last_updated: "2024-06-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.48, output: 1.48 }, - limit: { context: 8192, output: 8192 }, - }, - "sao10k/L3-8B-Stheno-v3.2": { - id: "sao10k/L3-8B-Stheno-v3.2", - name: "L3 8B Stheno V3.2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-29", - last_updated: "2024-11-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 8192, output: 32000 }, - }, - "sao10k/l3-8b-lunaris": { - id: "sao10k/l3-8b-lunaris", - name: "Sao10k L3 8B Lunaris\t", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-11-28", - last_updated: "2024-11-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 8192, output: 8192 }, - }, - "microsoft/wizardlm-2-8x22b": { - id: "microsoft/wizardlm-2-8x22b", - name: "Wizardlm 2 8x22B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-24", - last_updated: "2024-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.62, output: 0.62 }, - limit: { context: 65535, output: 8000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "OpenAI: GPT OSS 20B", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.15 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "OpenAI GPT OSS 120B", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.25 }, - limit: { context: 131072, output: 32768 }, - }, - "minimaxai/minimax-m1-80k": { - id: "minimaxai/minimax-m1-80k", - name: "MiniMax M1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 1000000, output: 40000 }, - }, - "xiaomimimo/mimo-v2-flash": { - id: "xiaomimimo/mimo-v2-flash", - name: "XiaomiMiMo/MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.3 }, - limit: { context: 262144, output: 32000 }, - }, - "baidu/ernie-4.5-vl-28b-a3b-thinking": { - id: "baidu/ernie-4.5-vl-28b-a3b-thinking", - name: "ERNIE-4.5-VL-28B-A3B-Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-11-26", - last_updated: "2025-11-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.39, output: 0.39 }, - limit: { context: 131072, output: 65536 }, - }, - "baidu/ernie-4.5-vl-424b-a47b": { - id: "baidu/ernie-4.5-vl-424b-a47b", - name: "ERNIE 4.5 VL 424B A47B", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.42, output: 1.25 }, - limit: { context: 123000, output: 16000 }, - }, - "baidu/ernie-4.5-21B-a3b": { - id: "baidu/ernie-4.5-21B-a3b", - name: "ERNIE 4.5 21B A3B", - family: "ernie", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 120000, output: 8000 }, - }, - "baidu/ernie-4.5-300b-a47b-paddle": { - id: "baidu/ernie-4.5-300b-a47b-paddle", - name: "ERNIE 4.5 300B A47B", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 123000, output: 12000 }, - }, - "baidu/ernie-4.5-21B-a3b-thinking": { - id: "baidu/ernie-4.5-21B-a3b-thinking", - name: "ERNIE-4.5-21B-A3B-Thinking", - family: "ernie", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-03", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131072, output: 65536 }, - }, - "baidu/ernie-4.5-vl-28b-a3b": { - id: "baidu/ernie-4.5-vl-28b-a3b", - name: "ERNIE 4.5 VL 28B A3B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 5.6 }, - limit: { context: 30000, output: 8000 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "MiniMax M2.7", - family: "minimax-m2.7", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "Minimax M2.1", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 204800, output: 131100 }, - }, - "minimax/minimax-m2.5-highspeed": { - id: "minimax/minimax-m2.5-highspeed", - name: "MiniMax M2.5 Highspeed", - family: "minimax-m2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.4, cache_read: 0.03 }, - limit: { context: 204800, output: 131100 }, - }, - "qwen/qwen2.5-7b-instruct": { - id: "qwen/qwen2.5-7b-instruct", - name: "Qwen2.5 7B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.07 }, - limit: { context: 32000, output: 32000 }, - }, - "qwen/qwen3.5-122b-a10b": { - id: "qwen/qwen3.5-122b-a10b", - name: "Qwen3.5-122B-A10B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 3.2 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3.6-27b": { - id: "qwen/qwen3.6-27b", - name: "Qwen3.6-27B", - family: "qwen3.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3.5-27b": { - id: "qwen/qwen3.5-27b", - name: "Qwen3.5-27B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.4 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-235b-a22b-instruct-2507": { - id: "qwen/qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.58 }, - limit: { context: 131072, output: 16384 }, - }, - "qwen/qwen3-omni-30b-a3b-instruct": { - id: "qwen/qwen3-omni-30b-a3b-instruct", - name: "Qwen3 Omni 30B A3B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "video", "audio", "image"], output: ["text", "audio"] }, - open_weights: true, - cost: { input: 0.25, output: 0.97, input_audio: 2.2, output_audio: 1.788 }, - limit: { context: 65536, output: 16384 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen3.5-397B-A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 64000 }, - }, - "qwen/qwen2.5-vl-72b-instruct": { - id: "qwen/qwen2.5-vl-72b-instruct", - name: "Qwen2.5 VL 72B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 0.8 }, - limit: { context: 32768, output: 32768 }, - }, - "qwen/qwen3-vl-235b-a22b-thinking": { - id: "qwen/qwen3-vl-235b-a22b-thinking", - name: "Qwen3 VL 235B A22B Thinking", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.98, output: 3.95 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-vl-30b-a3b-thinking": { - id: "qwen/qwen3-vl-30b-a3b-thinking", - name: "qwen/qwen3-vl-30b-a3b-thinking", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-11", - last_updated: "2025-10-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-omni-30b-a3b-thinking": { - id: "qwen/qwen3-omni-30b-a3b-thinking", - name: "Qwen3 Omni 30B A3B Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "audio", "video", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.97, input_audio: 2.2, output_audio: 1.788 }, - limit: { context: 65536, output: 16384 }, - }, - "qwen/qwen3-vl-8b-instruct": { - id: "qwen/qwen3-vl-8b-instruct", - name: "qwen/qwen3-vl-8b-instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-17", - last_updated: "2025-10-17", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.5 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-max": { - id: "qwen/qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.11, output: 8.45 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-32b-fp8": { - id: "qwen/qwen3-32b-fp8", - name: "Qwen3 32B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.45 }, - limit: { context: 40960, output: 20000 }, - }, - "qwen/qwen3-4b-fp8": { - id: "qwen/qwen3-4b-fp8", - name: "Qwen3 4B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.03 }, - limit: { context: 128000, output: 20000 }, - }, - "qwen/qwen3-235b-a22b-thinking-2507": { - id: "qwen/qwen3-235b-a22b-thinking-2507", - name: "Qwen3 235B A22b Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 3 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-next-80b-a3b-thinking": { - id: "qwen/qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-10", - last_updated: "2025-09-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen-mt-plus": { - id: "qwen/qwen-mt-plus", - name: "Qwen MT Plus", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-03", - last_updated: "2025-09-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.75 }, - limit: { context: 16384, output: 8192 }, - }, - "qwen/qwen3-next-80b-a3b-instruct": { - id: "qwen/qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-10", - last_updated: "2025-09-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-30b-a3b-fp8": { - id: "qwen/qwen3-30b-a3b-fp8", - name: "Qwen3 30B A3B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.45 }, - limit: { context: 40960, output: 20000 }, - }, - "qwen/qwen3-coder-next": { - id: "qwen/qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-03", - last_updated: "2026-02-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-coder-480b-a35b-instruct": { - id: "qwen/qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.3 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-vl-30b-a3b-instruct": { - id: "qwen/qwen3-vl-30b-a3b-instruct", - name: "qwen/qwen3-vl-30b-a3b-instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-11", - last_updated: "2025-10-11", - modalities: { input: ["text", "video", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.7 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-coder-30b-a3b-instruct": { - id: "qwen/qwen3-coder-30b-a3b-instruct", - name: "Qwen3 Coder 30b A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-09", - last_updated: "2025-10-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.27 }, - limit: { context: 160000, output: 32768 }, - }, - "qwen/qwen3-235b-a22b-fp8": { - id: "qwen/qwen3-235b-a22b-fp8", - name: "Qwen3 235B A22B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 40960, output: 20000 }, - }, - "qwen/qwen3-8b-fp8": { - id: "qwen/qwen3-8b-fp8", - name: "Qwen3 8B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.035, output: 0.138 }, - limit: { context: 128000, output: 20000 }, - }, - "qwen/qwen3-vl-235b-a22b-instruct": { - id: "qwen/qwen3-vl-235b-a22b-instruct", - name: "Qwen3 VL 235B A22B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen-2.5-72b-instruct": { - id: "qwen/qwen-2.5-72b-instruct", - name: "Qwen 2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-10-15", - last_updated: "2024-10-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.38, output: 0.4 }, - limit: { context: 32000, output: 8192 }, - }, - "qwen/qwen3.5-35b-a3b": { - id: "qwen/qwen3.5-35b-a3b", - name: "Qwen3.5-35B-A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2 }, - limit: { context: 262144, output: 65536 }, - }, - "kwaipilot/kat-coder-pro": { - id: "kwaipilot/kat-coder-pro", - name: "Kat Coder Pro", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-05", - last_updated: "2026-01-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 256000, output: 128000 }, - }, - "google/gemma-4-31b-it": { - id: "google/gemma-4-31b-it", - name: "Gemma 4 31B", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.4 }, - limit: { context: 262144, output: 131072 }, - }, - "google/gemma-3-12b-it": { - id: "google/gemma-3-12b-it", - name: "Gemma 3 12B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-25", - last_updated: "2025-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.119, output: 0.2 }, - limit: { context: 98304, output: 16384 }, - }, - "google/gemma-4-26b-a4b-it": { - id: "google/gemma-4-26b-a4b-it", - name: "Gemma 4 26B A4B", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4 }, - limit: { context: 262144, output: 131072 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-instruct": { - id: "moonshotai/kimi-k2-instruct", - name: "Kimi K2 Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.57, output: 2.3 }, - limit: { context: 131072, output: 131072 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-11-07", - last_updated: "2025-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek/deepseek-v4-flash": { - id: "deepseek/deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1048576, output: 393216 }, - }, - "deepseek/deepseek-v4-pro": { - id: "deepseek/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.69, output: 3.38, cache_read: 0.13 }, - limit: { context: 1048576, output: 393216 }, - }, - }, - }, - "xiaomi-token-plan-cn": { - id: "xiaomi-token-plan-cn", - env: ["XIAOMI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://token-plan-cn.xiaomimimo.com/v1", - name: "Xiaomi Token Plan (China)", - doc: "https://platform.xiaomimimo.com/#/docs", - models: { - "mimo-v2-tts": { - id: "mimo-v2-tts", - name: "MiMo-V2-TTS", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 16384 }, - }, - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - wandb: { - id: "wandb", - env: ["WANDB_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.inference.wandb.ai/v1", - name: "Weights & Biases", - doc: "https://docs.wandb.ai/guides/integrations/inference/", - models: { - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-28", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3-235B-A22B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen3-Coder-480B-A35B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 1.5 }, - limit: { context: 262144, output: 262144 }, - }, - "zai-org/GLM-5-FP8": { - id: "zai-org/GLM-5-FP8", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 200000, output: 200000 }, - }, - "meta-llama/Llama-4-Scout-17B-16E-Instruct": { - id: "meta-llama/Llama-4-Scout-17B-16E-Instruct", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-31", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.66 }, - limit: { context: 64000, output: 64000 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.71, output: 0.71 }, - limit: { context: 128000, output: 128000 }, - }, - "meta-llama/Llama-3.1-8B-Instruct": { - id: "meta-llama/Llama-3.1-8B-Instruct", - name: "Meta-Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.22 }, - limit: { context: 128000, output: 128000 }, - }, - "meta-llama/Llama-3.1-70B-Instruct": { - id: "meta-llama/Llama-3.1-70B-Instruct", - name: "Llama 3.1 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 0.8 }, - limit: { context: 128000, output: 128000 }, - }, - "OpenPipe/Qwen3-14B-Instruct": { - id: "OpenPipe/Qwen3-14B-Instruct", - name: "OpenPipe Qwen3 14B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22 }, - limit: { context: 32768, output: 32768 }, - }, - "microsoft/Phi-4-mini-instruct": { - id: "microsoft/Phi-4-mini-instruct", - name: "Phi-4-mini-instruct", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.35 }, - limit: { context: 128000, output: 128000 }, - }, - "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8": { - id: "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-FP8", - name: "NVIDIA Nemotron 3 Super 120B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-21", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 1.65 }, - limit: { context: 161000, output: 161000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "gpt-oss-20b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.2 }, - limit: { context: 131072, output: 131072 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "gpt-oss-120b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 131072 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.85 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196608, output: 196608 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 4.4, cache_read: 0.26, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - }, - }, - chutes: { - id: "chutes", - env: ["CHUTES_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://llm.chutes.ai/v1", - name: "Chutes", - doc: "https://llm.chutes.ai/v1/models", - models: { - "miromind-ai/MiroThinker-v1.5-235B": { - id: "miromind-ai/MiroThinker-v1.5-235B", - name: "MiroThinker V1.5 235B", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01-10", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.15 }, - limit: { context: 262144, output: 8192 }, - }, - "OpenGVLab/InternVL3-78B-TEE": { - id: "OpenGVLab/InternVL3-78B-TEE", - name: "InternVL3 78B TEE", - family: "opengvlab", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-01-06", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.39 }, - limit: { context: 32768, output: 32768 }, - }, - "NousResearch/DeepHermes-3-Mistral-24B-Preview": { - id: "NousResearch/DeepHermes-3-Mistral-24B-Preview", - name: "DeepHermes 3 Mistral 24B Preview", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.1 }, - limit: { context: 32768, output: 32768 }, - }, - "NousResearch/Hermes-4-405B-FP8-TEE": { - id: "NousResearch/Hermes-4-405B-FP8-TEE", - name: "Hermes 4 405B FP8 TEE", - family: "nousresearch", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 131072, output: 65536 }, - }, - "NousResearch/Hermes-4.3-36B": { - id: "NousResearch/Hermes-4.3-36B", - name: "Hermes 4.3 36B", - family: "nousresearch", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.39 }, - limit: { context: 32768, output: 8192 }, - }, - "NousResearch/Hermes-4-14B": { - id: "NousResearch/Hermes-4-14B", - name: "Hermes 4 14B", - family: "nousresearch", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.05 }, - limit: { context: 40960, output: 40960 }, - }, - "NousResearch/Hermes-4-70B": { - id: "NousResearch/Hermes-4-70B", - name: "Hermes 4 70B", - family: "nousresearch", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.38 }, - limit: { context: 131072, output: 131072 }, - }, - "Qwen/Qwen3-30B-A3B": { - id: "Qwen/Qwen3-30B-A3B", - name: "Qwen3 30B A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.22 }, - limit: { context: 40960, output: 40960 }, - }, - "Qwen/Qwen3-Coder-Next": { - id: "Qwen/Qwen3-Coder-Next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.3 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen2.5-Coder-32B-Instruct": { - id: "Qwen/Qwen2.5-Coder-32B-Instruct", - name: "Qwen2.5 Coder 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.11 }, - limit: { context: 32768, output: 32768 }, - }, - "Qwen/Qwen3-235B-A22B": { - id: "Qwen/Qwen3-235B-A22B", - name: "Qwen3 235B A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 40960, output: 40960 }, - }, - "Qwen/Qwen2.5-VL-72B-Instruct-TEE": { - id: "Qwen/Qwen2.5-VL-72B-Instruct-TEE", - name: "Qwen2.5 VL 72B Instruct TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 32768, output: 32768 }, - }, - "Qwen/Qwen3Guard-Gen-0.6B": { - id: "Qwen/Qwen3Guard-Gen-0.6B", - name: "Qwen3Guard Gen 0.6B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.01, cache_read: 0.005 }, - limit: { context: 32768, output: 8192 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Instruct": { - id: "Qwen/Qwen3-Next-80B-A3B-Instruct", - name: "Qwen3 Next 80B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.8 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.33 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-32B": { - id: "Qwen/Qwen3-32B", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.24, cache_read: 0.04 }, - limit: { context: 40960, output: 40960 }, - }, - "Qwen/Qwen3-14B": { - id: "Qwen/Qwen3-14B", - name: "Qwen3 14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22 }, - limit: { context: 40960, output: 40960 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE", - name: "Qwen3 235B A22B Instruct 2507 TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.55, cache_read: 0.04 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3 235B A22B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen2.5-VL-32B-Instruct": { - id: "Qwen/Qwen2.5-VL-32B-Instruct", - name: "Qwen2.5 VL 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22 }, - limit: { context: 16384, output: 16384 }, - }, - "Qwen/Qwen3.5-397B-A17B-TEE": { - id: "Qwen/Qwen3.5-397B-A17B-TEE", - name: "Qwen3.5 397B A17B TEE", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-18", - last_updated: "2026-02-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.39, output: 2.34, cache_read: 0.195 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8-TEE", - name: "Qwen3 Coder 480B A35B Instruct FP8 TEE", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.95, cache_read: 0.11 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Instruct": { - id: "Qwen/Qwen3-VL-235B-A22B-Instruct", - name: "Qwen3 VL 235B A22B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen2.5-72B-Instruct": { - id: "Qwen/Qwen2.5-72B-Instruct", - name: "Qwen2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 32768, output: 32768 }, - }, - "zai-org/GLM-5.1-TEE": { - id: "zai-org/GLM-5.1-TEE", - name: "GLM 5.1 TEE", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 3.15, cache_read: 0.475 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.7-Flash": { - id: "zai-org/GLM-4.7-Flash", - name: "GLM 4.7 Flash", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.35 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.5-TEE": { - id: "zai-org/GLM-4.5-TEE", - name: "GLM 4.5 TEE", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.55 }, - limit: { context: 131072, output: 65536 }, - }, - "zai-org/GLM-4.6-FP8": { - id: "zai-org/GLM-4.6-FP8", - name: "GLM 4.6 FP8", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.5-Air": { - id: "zai-org/GLM-4.5-Air", - name: "GLM 4.5 Air", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22 }, - limit: { context: 131072, output: 131072 }, - }, - "zai-org/GLM-4.7-FP8": { - id: "zai-org/GLM-4.7-FP8", - name: "GLM 4.7 FP8", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-5-TEE": { - id: "zai-org/GLM-5-TEE", - name: "GLM 5 TEE", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 3.15, cache_read: 0.475 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.5-FP8": { - id: "zai-org/GLM-4.5-FP8", - name: "GLM 4.5 FP8", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 131072, output: 65536 }, - }, - "zai-org/GLM-4.7-TEE": { - id: "zai-org/GLM-4.7-TEE", - name: "GLM 4.7 TEE", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.5 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.6V": { - id: "zai-org/GLM-4.6V", - name: "GLM 4.6V", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9, cache_read: 0.15 }, - limit: { context: 131072, output: 65536 }, - }, - "zai-org/GLM-5-Turbo": { - id: "zai-org/GLM-5-Turbo", - name: "GLM 5 Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.49, output: 1.96, cache_read: 0.245 }, - limit: { context: 202752, output: 65535 }, - }, - "zai-org/GLM-4.6-TEE": { - id: "zai-org/GLM-4.6-TEE", - name: "GLM 4.6 TEE", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.7, cache_read: 0.2 }, - limit: { context: 202752, output: 65536 }, - }, - "mistralai/Devstral-2-123B-Instruct-2512-TEE": { - id: "mistralai/Devstral-2-123B-Instruct-2512-TEE", - name: "Devstral 2 123B Instruct 2512 TEE", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-10", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.22 }, - limit: { context: 262144, output: 65536 }, - }, - "XiaomiMiMo/MiMo-V2-Flash": { - id: "XiaomiMiMo/MiMo-V2-Flash", - name: "MiMo V2 Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.29 }, - limit: { context: 262144, output: 32000 }, - }, - "chutesai/Mistral-Small-3.2-24B-Instruct-2506": { - id: "chutesai/Mistral-Small-3.2-24B-Instruct-2506", - name: "Mistral Small 3.2 24B Instruct 2506", - family: "chutesai", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.18 }, - limit: { context: 131072, output: 131072 }, - }, - "chutesai/Mistral-Small-3.1-24B-Instruct-2503": { - id: "chutesai/Mistral-Small-3.1-24B-Instruct-2503", - name: "Mistral Small 3.1 24B Instruct 2503", - family: "chutesai", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.11, cache_read: 0.015 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16": { - id: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16", - name: "NVIDIA Nemotron 3 Nano 30B A3B BF16", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.24 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-ai/DeepSeek-R1-TEE": { - id: "deepseek-ai/DeepSeek-R1-TEE", - name: "DeepSeek R1 TEE", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek-ai/DeepSeek-V3": { - id: "deepseek-ai/DeepSeek-V3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek-ai/DeepSeek-R1-Distill-Llama-70B": { - id: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.11 }, - limit: { context: 131072, output: 131072 }, - }, - "deepseek-ai/DeepSeek-V3.1-TEE": { - id: "deepseek-ai/DeepSeek-V3.1-TEE", - name: "DeepSeek V3.1 TEE", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3-0324-TEE": { - id: "deepseek-ai/DeepSeek-V3-0324-TEE", - name: "DeepSeek V3 0324 TEE", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.19, output: 0.87, cache_read: 0.095 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3.2-Speciale-TEE": { - id: "deepseek-ai/DeepSeek-V3.2-Speciale-TEE", - name: "DeepSeek V3.2 Speciale TEE", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus-TEE": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus-TEE", - name: "DeepSeek V3.1 Terminus TEE", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.23, output: 0.9 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-R1-0528-TEE": { - id: "deepseek-ai/DeepSeek-R1-0528-TEE", - name: "DeepSeek R1 0528 TEE", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.75 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/DeepSeek-V3.2-TEE": { - id: "deepseek-ai/DeepSeek-V3.2-TEE", - name: "DeepSeek V3.2 TEE", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 0.42, cache_read: 0.14 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "gpt oss 20b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.1 }, - limit: { context: 131072, output: 131072 }, - }, - "openai/gpt-oss-120b-TEE": { - id: "openai/gpt-oss-120b-TEE", - name: "gpt oss 120b TEE", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.18 }, - limit: { context: 131072, output: 65536 }, - }, - "unsloth/gemma-3-12b-it": { - id: "unsloth/gemma-3-12b-it", - name: "gemma 3 12b it", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.1 }, - limit: { context: 131072, output: 131072 }, - }, - "unsloth/Llama-3.2-3B-Instruct": { - id: "unsloth/Llama-3.2-3B-Instruct", - name: "Llama 3.2 3B Instruct", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-02-12", - last_updated: "2025-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.01, cache_read: 0.005 }, - limit: { context: 16384, output: 16384 }, - }, - "unsloth/gemma-3-4b-it": { - id: "unsloth/gemma-3-4b-it", - name: "gemma 3 4b it", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.03 }, - limit: { context: 96000, output: 96000 }, - }, - "unsloth/Llama-3.2-1B-Instruct": { - id: "unsloth/Llama-3.2-1B-Instruct", - name: "Llama 3.2 1B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.01, cache_read: 0.005 }, - limit: { context: 32768, output: 8192 }, - }, - "unsloth/Mistral-Nemo-Instruct-2407": { - id: "unsloth/Mistral-Nemo-Instruct-2407", - name: "Mistral Nemo Instruct 2407", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04, cache_read: 0.01 }, - limit: { context: 131072, output: 131072 }, - }, - "unsloth/Mistral-Small-24B-Instruct-2501": { - id: "unsloth/Mistral-Small-24B-Instruct-2501", - name: "Mistral Small 24B Instruct 2501", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.11 }, - limit: { context: 32768, output: 32768 }, - }, - "unsloth/gemma-3-27b-it": { - id: "unsloth/gemma-3-27b-it", - name: "gemma 3 27b it", - family: "unsloth", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.15, cache_read: 0.02 }, - limit: { context: 128000, output: 65536 }, - }, - "moonshotai/Kimi-K2-Thinking-TEE": { - id: "moonshotai/Kimi-K2-Thinking-TEE", - name: "Kimi K2 Thinking TEE", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.75 }, - limit: { context: 262144, output: 65535 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 Instruct 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.39, output: 1.9, cache_read: 0.195 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.6-TEE": { - id: "moonshotai/Kimi-K2.6-TEE", - name: "Kimi K2.6 TEE", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-04-20", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.44, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.5-TEE": { - id: "moonshotai/Kimi-K2.5-TEE", - name: "Kimi K2.5 TEE", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 65535 }, - }, - "MiniMaxAI/MiniMax-M2.1-TEE": { - id: "MiniMaxAI/MiniMax-M2.1-TEE", - name: "MiniMax M2.1 TEE", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1.12 }, - limit: { context: 196608, output: 65536 }, - }, - "MiniMaxAI/MiniMax-M2.5-TEE": { - id: "MiniMaxAI/MiniMax-M2.5-TEE", - name: "MiniMax M2.5 TEE", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.1, cache_read: 0.15 }, - limit: { context: 196608, output: 65536 }, - }, - "rednote-hilab/dots.ocr": { - id: "rednote-hilab/dots.ocr", - name: "dots.ocr", - family: "rednote", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.01, cache_read: 0.005 }, - limit: { context: 131072, output: 131072 }, - }, - "tngtech/TNG-R1T-Chimera-Turbo": { - id: "tngtech/TNG-R1T-Chimera-Turbo", - name: "TNG R1T Chimera Turbo", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.6 }, - limit: { context: 163840, output: 65536 }, - }, - "tngtech/DeepSeek-TNG-R1T2-Chimera": { - id: "tngtech/DeepSeek-TNG-R1T2-Chimera", - name: "DeepSeek TNG R1T2 Chimera", - family: "tngtech", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.85 }, - limit: { context: 163840, output: 163840 }, - }, - "tngtech/DeepSeek-R1T-Chimera": { - id: "tngtech/DeepSeek-R1T-Chimera", - name: "DeepSeek R1T Chimera", - family: "tngtech", - attachment: false, - reasoning: true, - tool_call: false, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 163840, output: 163840 }, - }, - "tngtech/TNG-R1T-Chimera-TEE": { - id: "tngtech/TNG-R1T-Chimera-TEE", - name: "TNG R1T Chimera TEE", - family: "tngtech", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.85 }, - limit: { context: 163840, output: 65536 }, - }, - }, - }, - dinference: { - id: "dinference", - env: ["DINFERENCE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.dinference.com/v1", - name: "DInference", - doc: "https://dinference.com", - models: { - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08", - last_updated: "2025-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0675, output: 0.27 }, - limit: { context: 131072, output: 32768 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 1.65 }, - limit: { context: 200000, output: 128000 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 2.4 }, - limit: { context: 200000, output: 128000 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 3.89 }, - limit: { context: 200000, output: 128000 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.88 }, - limit: { context: 200000, output: 32000 }, - }, - }, - }, - vivgrid: { - id: "vivgrid", - env: ["VIVGRID_API_KEY"], - npm: "@ai-sdk/openai", - api: "https://api.vivgrid.com/v1", - name: "Vivgrid", - doc: "https://docs.vivgrid.com/models", - models: { - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-3.1-flash-lite-preview": { - id: "gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 0.42 }, - limit: { context: 128000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - provider: { npm: "@ai-sdk/openai-compatible" }, - }, - }, - }, - deepinfra: { - id: "deepinfra", - env: ["DEEPINFRA_API_KEY"], - npm: "@ai-sdk/deepinfra", - name: "Deep Infra", - doc: "https://deepinfra.com/models", - models: { - "Qwen/Qwen3.5-397B-A17B": { - id: "Qwen/Qwen3.5-397B-A17B", - name: "Qwen 3.5 397B A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-01", - last_updated: "2026-04-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.54, output: 3.4 }, - limit: { context: 262144, output: 81920 }, - }, - "Qwen/Qwen3.5-35B-A3B": { - id: "Qwen/Qwen3.5-35B-A3B", - name: "Qwen 3.5 35B A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-01", - last_updated: "2026-04-20", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.95 }, - limit: { context: 262144, output: 81920 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo", - name: "Qwen3 Coder 480B A35B Instruct Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 262144, output: 66536 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.6 }, - limit: { context: 262144, output: 66536 }, - }, - "Qwen/Qwen3.6-35B-A3B": { - id: "Qwen/Qwen3.6-35B-A3B", - name: "Qwen3.6 35B A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1 }, - limit: { context: 262144, output: 81920 }, - }, - "zai-org/GLM-4.7-Flash": { - id: "zai-org/GLM-4.7-Flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4 }, - limit: { context: 202752, output: 16384 }, - }, - "zai-org/GLM-4.5": { - id: "zai-org/GLM-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 131072, output: 98304 }, - status: "deprecated", - }, - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.43, output: 1.75, cache_read: 0.08 }, - limit: { context: 202752, output: 16384 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202752, output: 16384 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-12", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.56, cache_read: 0.16 }, - limit: { context: 202752, output: 16384 }, - }, - "zai-org/GLM-4.6V": { - id: "zai-org/GLM-4.6V", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.43, output: 1.74, cache_read: 0.08 }, - limit: { context: 204800, output: 131072 }, - }, - "meta-llama/Llama-4-Scout-17B-16E-Instruct": { - id: "meta-llama/Llama-4-Scout-17B-16E-Instruct", - name: "Llama 4 Scout 17B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.3 }, - limit: { context: 10000000, output: 16384 }, - }, - "meta-llama/Llama-3.1-8B-Instruct": { - id: "meta-llama/Llama-3.1-8B-Instruct", - name: "Llama 3.1 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.05 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/Llama-3.1-70B-Instruct": { - id: "meta-llama/Llama-3.1-70B-Instruct", - name: "Llama 3.1 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/Llama-3.1-8B-Instruct-Turbo": { - id: "meta-llama/Llama-3.1-8B-Instruct-Turbo", - name: "Llama 3.1 8B Turbo", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.03 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/Llama-3.3-70B-Instruct-Turbo": { - id: "meta-llama/Llama-3.3-70B-Instruct-Turbo", - name: "Llama 3.3 70B Turbo", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.32 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": { - id: "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", - name: "Llama 4 Maverick 17B FP8", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 1000000, output: 16384 }, - }, - "meta-llama/Llama-3.1-70B-Instruct-Turbo": { - id: "meta-llama/Llama-3.1-70B-Instruct-Turbo", - name: "Llama 3.1 70B Turbo", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 131072, output: 16384 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek-R1-0528", - attachment: false, - reasoning: true, - tool_call: false, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.15, cache_read: 0.35 }, - limit: { context: 163840, output: 64000 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek-V3.2", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.26, output: 0.38, cache_read: 0.13 }, - limit: { context: 163840, output: 64000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.14 }, - limit: { context: 131072, output: 16384 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.24 }, - limit: { context: 131072, output: 16384 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2025-11-06", - last_updated: "2025-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.47, output: 2 }, - limit: { context: 131072, output: 32768 }, - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 3.5, cache_read: 0.15 }, - limit: { context: 262144, output: 16384 }, - }, - "moonshotai/Kimi-K2-Instruct": { - id: "moonshotai/Kimi-K2-Instruct", - name: "Kimi K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2 }, - limit: { context: 131072, output: 32768 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.8 }, - limit: { context: 262144, output: 32768 }, - }, - "MiniMaxAI/MiniMax-M2": { - id: "MiniMaxAI/MiniMax-M2", - name: "MiniMax M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.254, output: 1.02 }, - limit: { context: 262144, output: 32768 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-06", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.95, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMaxAI/MiniMax-M2.1": { - id: "MiniMaxAI/MiniMax-M2.1", - name: "MiniMax M2.1", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.2 }, - limit: { context: 196608, output: 196608 }, - }, - "anthropic/claude-3-7-sonnet-latest": { - id: "anthropic/claude-3-7-sonnet-latest", - name: "Claude Sonnet 3.7 (Latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.3, output: 16.5, cache_read: 0.33 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-4-opus": { - id: "anthropic/claude-4-opus", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-06-12", - last_updated: "2025-06-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 16.5, output: 82.5 }, - limit: { context: 200000, output: 32000 }, - }, - "deepseek-ai/DeepSeek-V4-Flash": { - id: "deepseek-ai/DeepSeek-V4-Flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek-ai/DeepSeek-V4-Pro": { - id: "deepseek-ai/DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 65536, output: 65536 }, - }, - "google/gemma-4-26B-A4B-it": { - id: "google/gemma-4-26B-A4B-it", - name: "Gemma 4 26B", - family: "gemma", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.34 }, - limit: { context: 256000, output: 8192 }, - }, - "google/gemma-4-31B-it": { - id: "google/gemma-4-31B-it", - name: "Gemma 4 31B", - family: "gemma", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.38 }, - limit: { context: 256000, output: 8192 }, - }, - }, - }, - "qiniu-ai": { - id: "qiniu-ai", - env: ["QINIU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.qnaigc.com/v1", - name: "Qiniu", - doc: "https://developer.qiniu.com/aitokenapi", - models: { - "qwen3-235b-a22b": { - id: "qwen3-235b-a22b", - name: "Qwen 3 235B A22B", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "doubao-seed-1.6-flash": { - id: "doubao-seed-1.6-flash", - name: "Doubao-Seed 1.6 Flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-15", - last_updated: "2025-08-15", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235b A22B Instruct 2507", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 262144, output: 64000 }, - }, - "doubao-seed-2.0-code": { - id: "doubao-seed-2.0-code", - name: "Doubao Seed 2.0 Code", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 128000 }, - }, - "deepseek-v3-0324": { - id: "deepseek-v3-0324", - name: "DeepSeek-V3-0324", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 16000 }, - }, - "doubao-1.5-thinking-pro": { - id: "doubao-1.5-thinking-pro", - name: "Doubao 1.5 Thinking Pro", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 16000 }, - }, - "claude-3.7-sonnet": { - id: "claude-3.7-sonnet", - name: "Claude 3.7 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 128000 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-22", - last_updated: "2026-02-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 64000 }, - }, - "qwen-vl-max-2025-01-25": { - id: "qwen-vl-max-2025-01-25", - name: "Qwen VL-MAX-2025-01-25", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 4096 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 40000, output: 4096 }, - }, - "doubao-1.5-pro-32k": { - id: "doubao-1.5-pro-32k", - name: "Doubao 1.5 Pro 32k", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 12000 }, - }, - "qwen2.5-vl-72b-instruct": { - id: "qwen2.5-vl-72b-instruct", - name: "Qwen 2.5 VL 72B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 8192 }, - }, - "gemini-2.0-flash": { - id: "gemini-2.0-flash", - name: "Gemini 2.0 Flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 1048576, output: 8192 }, - }, - "qwen3-vl-30b-a3b-thinking": { - id: "qwen3-vl-30b-a3b-thinking", - name: "Qwen3-Vl 30b A3b Thinking", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-09", - last_updated: "2026-02-09", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "gemini-3.0-pro-image-preview": { - id: "gemini-3.0-pro-image-preview", - name: "Gemini 3.0 Pro Image Preview", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 32768, output: 8192 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - limit: { context: 1048576, output: 65536 }, - }, - "claude-4.5-opus": { - id: "claude-4.5-opus", - name: "Claude 4.5 Opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 200000 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek-R1", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "claude-4.0-opus": { - id: "claude-4.0-opus", - name: "Claude 4.0 Opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 32000 }, - }, - "claude-4.5-haiku": { - id: "claude-4.5-haiku", - name: "Claude 4.5 Haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-10-16", - last_updated: "2025-10-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3 Max", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 262144, output: 65536 }, - }, - "gemini-3.0-flash-preview": { - id: "gemini-3.0-flash-preview", - name: "Gemini 3.0 Flash Preview", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - limit: { context: 1000000, output: 64000 }, - }, - "gemini-2.5-flash-image": { - id: "gemini-2.5-flash-image", - name: "Gemini 2.5 Flash Image", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-10-22", - last_updated: "2025-10-22", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 32768, output: 8192 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM 4.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 131072, output: 98304 }, - }, - "claude-3.5-sonnet": { - id: "claude-3.5-sonnet", - name: "Claude 3.5 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-09", - last_updated: "2025-09-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 8200 }, - }, - "claude-4.0-sonnet": { - id: "claude-4.0-sonnet", - name: "Claude 4.0 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-30b-a3b-instruct-2507": { - id: "qwen3-30b-a3b-instruct-2507", - name: "Qwen3 30b A3b Instruct 2507", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-04", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "doubao-seed-1.6-thinking": { - id: "doubao-seed-1.6-thinking", - name: "Doubao-Seed 1.6 Thinking", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-15", - last_updated: "2025-08-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 1048576, output: 64000 }, - }, - "qwen3-235b-a22b-thinking-2507": { - id: "qwen3-235b-a22b-thinking-2507", - name: "Qwen3 235B A22B Thinking 2507", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 262144, output: 4096 }, - }, - "qwen3-next-80b-a3b-thinking": { - id: "qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-12", - last_updated: "2025-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 131072, output: 32768 }, - }, - "qwen3-30b-a3b-thinking-2507": { - id: "qwen3-30b-a3b-thinking-2507", - name: "Qwen3 30b A3b Thinking 2507", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-04", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 126000, output: 32000 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM 4.5 Air", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 131000, output: 4096 }, - }, - "deepseek-v3.1": { - id: "deepseek-v3.1", - name: "DeepSeek-V3.1", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "qwen3-30b-a3b": { - id: "qwen3-30b-a3b", - name: "Qwen3 30B A3B", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 40000, output: 4096 }, - }, - "claude-4.1-opus": { - id: "claude-4.1-opus", - name: "Claude 4.1 Opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 32000 }, - }, - "doubao-seed-2.0-mini": { - id: "doubao-seed-2.0-mini", - name: "Doubao Seed 2.0 Mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "qwen3-next-80b-a3b-instruct": { - id: "qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-12", - last_updated: "2025-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 131072, output: 32768 }, - }, - "doubao-seed-1.6": { - id: "doubao-seed-1.6", - name: "Doubao-Seed 1.6", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-15", - last_updated: "2025-08-15", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "qwen2.5-vl-7b-instruct": { - id: "qwen2.5-vl-7b-instruct", - name: "Qwen 2.5 VL 7B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 8192 }, - }, - "kling-v2-6": { - id: "kling-v2-6", - name: "Kling-V2 6", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-01-13", - last_updated: "2026-01-13", - modalities: { input: ["text", "image", "video"], output: ["video"] }, - open_weights: false, - limit: { context: 99999999, output: 99999999 }, - }, - "MiniMax-M1": { - id: "MiniMax-M1", - name: "MiniMax M1", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 1000000, output: 80000 }, - }, - "gemini-3.0-pro-preview": { - id: "gemini-3.0-pro-preview", - name: "Gemini 3.0 Pro Preview", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image", "video", "pdf", "audio"], output: ["text"] }, - open_weights: false, - limit: { context: 1000000, output: 64000 }, - }, - "doubao-seed-2.0-lite": { - id: "doubao-seed-2.0-lite", - name: "Doubao Seed 2.0 Lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-14", - last_updated: "2025-08-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 262000, output: 4096 }, - }, - "claude-3.5-haiku": { - id: "claude-3.5-haiku", - name: "Claude 3.5 Haiku", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 8192 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "gpt-oss-20b", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 4096 }, - }, - "qwen-turbo": { - id: "qwen-turbo", - name: "Qwen-Turbo", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 1000000, output: 4096 }, - }, - "kimi-k2": { - id: "kimi-k2", - name: "Kimi K2", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 128000 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 1048576, output: 64000 }, - }, - "qwen3-max-preview": { - id: "qwen3-max-preview", - name: "Qwen3 Max Preview", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-06", - last_updated: "2025-09-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 64000 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "gpt-oss-120b", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 4096 }, - }, - "doubao-1.5-vision-pro": { - id: "doubao-1.5-vision-pro", - name: "Doubao 1.5 Vision Pro", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 16000 }, - }, - "claude-4.5-sonnet": { - id: "claude-4.5-sonnet", - name: "Claude 4.5 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 64000 }, - }, - "deepseek-v3": { - id: "deepseek-v3", - name: "DeepSeek-V3", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-08-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 16000 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek-R1-0528", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 1048576, output: 8192 }, - }, - "qwen-max-2025-01-25": { - id: "qwen-max-2025-01-25", - name: "Qwen2.5-Max-2025-01-25", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 4096 }, - }, - "doubao-seed-2.0-pro": { - id: "doubao-seed-2.0-pro", - name: "Doubao Seed 2.0 Pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 128000 }, - }, - "deepseek/deepseek-v3.2-exp-thinking": { - id: "deepseek/deepseek-v3.2-exp-thinking", - name: "DeepSeek/DeepSeek-V3.2-Exp-Thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "deepseek/deepseek-v3.1-terminus-thinking": { - id: "deepseek/deepseek-v3.1-terminus-thinking", - name: "DeepSeek/DeepSeek-V3.1-Terminus-Thinking", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "deepseek/deepseek-v3.2-exp": { - id: "deepseek/deepseek-v3.2-exp", - name: "DeepSeek/DeepSeek-V3.2-Exp", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "deepseek/deepseek-v3.2-251201": { - id: "deepseek/deepseek-v3.2-251201", - name: "Deepseek/DeepSeek-V3.2", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "deepseek/deepseek-math-v2": { - id: "deepseek/deepseek-math-v2", - name: "Deepseek/Deepseek-Math-V2", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-12-04", - last_updated: "2025-12-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 160000, output: 160000 }, - }, - "deepseek/deepseek-v3.1-terminus": { - id: "deepseek/deepseek-v3.1-terminus", - name: "DeepSeek/DeepSeek-V3.1-Terminus", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 32000 }, - }, - "stepfun-ai/gelab-zero-4b-preview": { - id: "stepfun-ai/gelab-zero-4b-preview", - name: "Stepfun-Ai/Gelab Zero 4b Preview", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 8192, output: 4096 }, - }, - "stepfun/step-3.5-flash": { - id: "stepfun/step-3.5-flash", - name: "Stepfun/Step-3.5 Flash", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 64000, output: 4096 }, - }, - "x-ai/grok-4-fast": { - id: "x-ai/grok-4-fast", - name: "x-AI/Grok-4-Fast", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-20", - last_updated: "2025-09-20", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-code-fast-1": { - id: "x-ai/grok-code-fast-1", - name: "x-AI/Grok-Code-Fast 1", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-02", - last_updated: "2025-09-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 10000 }, - }, - "x-ai/grok-4-fast-reasoning": { - id: "x-ai/grok-4-fast-reasoning", - name: "X-Ai/Grok-4-Fast-Reasoning", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-4.1-fast-non-reasoning": { - id: "x-ai/grok-4.1-fast-non-reasoning", - name: "X-Ai/Grok 4.1 Fast Non Reasoning", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-4.1-fast": { - id: "x-ai/grok-4.1-fast", - name: "x-AI/Grok-4.1-Fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-11-20", - last_updated: "2025-11-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-4-fast-non-reasoning": { - id: "x-ai/grok-4-fast-non-reasoning", - name: "X-Ai/Grok-4-Fast-Non-Reasoning", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-4.1-fast-reasoning": { - id: "x-ai/grok-4.1-fast-reasoning", - name: "X-Ai/Grok 4.1 Fast Reasoning", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 20000000, output: 2000000 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "OpenAI/GPT-5.2", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "OpenAI/GPT-5", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 400000, output: 128000 }, - }, - "z-ai/glm-4.7": { - id: "z-ai/glm-4.7", - name: "Z-Ai/GLM 4.7", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 200000 }, - }, - "z-ai/glm-5": { - id: "z-ai/glm-5", - name: "Z-Ai/GLM 5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 128000 }, - }, - "z-ai/autoglm-phone-9b": { - id: "z-ai/autoglm-phone-9b", - name: "Z-Ai/Autoglm Phone 9b", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 12800, output: 4096 }, - }, - "z-ai/glm-4.6": { - id: "z-ai/glm-4.6", - name: "Z-AI/GLM 4.6", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-10-11", - last_updated: "2025-10-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 200000 }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "Minimax/Minimax-M2", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-10-28", - last_updated: "2025-10-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 128000 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "Minimax/Minimax-M2.1", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 204800, output: 128000 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "Minimax/Minimax-M2.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 204800, output: 128000 }, - }, - "minimax/minimax-m2.5-highspeed": { - id: "minimax/minimax-m2.5-highspeed", - name: "Minimax/Minimax-M2.5 Highspeed", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-14", - last_updated: "2026-02-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 204800, output: 128000 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Moonshotai/Kimi-K2.5", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-01-28", - last_updated: "2026-01-28", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 256000 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 0905", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-09-08", - last_updated: "2025-09-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 100000 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-11-07", - last_updated: "2025-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 100000 }, - }, - "meituan/longcat-flash-chat": { - id: "meituan/longcat-flash-chat", - name: "Meituan/Longcat-Flash-Chat", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-11-05", - last_updated: "2025-11-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 131072, output: 131072 }, - }, - "meituan/longcat-flash-lite": { - id: "meituan/longcat-flash-lite", - name: "Meituan/Longcat-Flash-Lite", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 320000 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "Mimo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 256000, output: 256000 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "Xiaomi/Mimo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 256000, output: 256000 }, - }, - }, - }, - kilo: { - id: "kilo", - env: ["KILO_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.kilo.ai/api/gateway", - name: "Kilo Gateway", - doc: "https://kilo.ai", - models: { - "rekaai/reka-edge": { - id: "rekaai/reka-edge", - name: "Reka Edge", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-20", - last_updated: "2026-04-11", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 16384, output: 16384 }, - }, - "rekaai/reka-flash-3": { - id: "rekaai/reka-flash-3", - name: "Reka Flash 3", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-03-12", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.2 }, - limit: { context: 65536, output: 65536 }, - }, - "ai21/jamba-large-1.7": { - id: "ai21/jamba-large-1.7", - name: "AI21: Jamba Large 1.7", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-09", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 256000, output: 4096 }, - }, - "alibaba/tongyi-deepresearch-30b-a3b": { - id: "alibaba/tongyi-deepresearch-30b-a3b", - name: "Tongyi DeepResearch 30B A3B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.45 }, - limit: { context: 131072, output: 131072 }, - }, - "inflection/inflection-3-pi": { - id: "inflection/inflection-3-pi", - name: "Inflection: Inflection 3 Pi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-10-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 8000, output: 1024 }, - }, - "inflection/inflection-3-productivity": { - id: "inflection/inflection-3-productivity", - name: "Inflection: Inflection 3 Productivity", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-10-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 8000, output: 1024 }, - }, - "liquid/lfm-2-24b-a2b": { - id: "liquid/lfm-2-24b-a2b", - name: "LiquidAI: LFM2-24B-A2B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.12 }, - limit: { context: 32768, output: 32768 }, - }, - "writer/palmyra-x5": { - id: "writer/palmyra-x5", - name: "Writer: Palmyra X5", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 6 }, - limit: { context: 1040000, output: 8192 }, - }, - "ibm-granite/granite-4.1-8b": { - id: "ibm-granite/granite-4.1-8b", - name: "IBM: Granite 4.1 8B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-30", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.1, cache_read: 0.05 }, - limit: { context: 131072, output: 131072 }, - }, - "ibm-granite/granite-4.0-h-micro": { - id: "ibm-granite/granite-4.0-h-micro", - name: "IBM: Granite 4.0 Micro", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-20", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.017, output: 0.11 }, - limit: { context: 131000, output: 32768 }, - }, - "essentialai/rnj-1-instruct": { - id: "essentialai/rnj-1-instruct", - name: "EssentialAI: Rnj 1 Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-05", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 32768, output: 6554 }, - }, - "perplexity/sonar-pro": { - id: "perplexity/sonar-pro", - name: "Perplexity: Sonar Pro", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8000 }, - }, - "perplexity/sonar-deep-research": { - id: "perplexity/sonar-deep-research", - name: "Perplexity: Sonar Deep Research", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 128000, output: 25600 }, - }, - "perplexity/sonar": { - id: "perplexity/sonar", - name: "Perplexity: Sonar", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 127072, output: 25415 }, - }, - "perplexity/sonar-pro-search": { - id: "perplexity/sonar-pro-search", - name: "Perplexity: Sonar Pro Search", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-10-31", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8000 }, - }, - "perplexity/sonar-reasoning-pro": { - id: "perplexity/sonar-reasoning-pro", - name: "Perplexity: Sonar Reasoning Pro", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 128000, output: 25600 }, - }, - "deepseek/deepseek-chat-v3.1": { - id: "deepseek/deepseek-chat-v3.1", - name: "DeepSeek: DeepSeek V3.1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.75 }, - limit: { context: 32768, output: 7168 }, - }, - "deepseek/deepseek-chat": { - id: "deepseek/deepseek-chat", - name: "DeepSeek: DeepSeek V3", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.32, output: 0.89, cache_read: 0.15 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-r1-distill-llama-70b": { - id: "deepseek/deepseek-r1-distill-llama-70b", - name: "DeepSeek: R1 Distill Llama 70B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-01-23", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 0.8, cache_read: 0.015 }, - limit: { context: 131072, output: 16384 }, - }, - "deepseek/deepseek-r1": { - id: "deepseek/deepseek-r1", - name: "DeepSeek: R1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.5 }, - limit: { context: 64000, output: 16000 }, - }, - "deepseek/deepseek-v3.2-speciale": { - id: "deepseek/deepseek-v3.2-speciale", - name: "DeepSeek: DeepSeek V3.2 Speciale", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-12-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.2, cache_read: 0.135 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-r1-distill-qwen-32b": { - id: "deepseek/deepseek-r1-distill-qwen-32b", - name: "DeepSeek: R1 Distill Qwen 32B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 0.29 }, - limit: { context: 32768, output: 32768 }, - }, - "deepseek/deepseek-v3.2-exp": { - id: "deepseek/deepseek-v3.2-exp", - name: "DeepSeek: DeepSeek V3.2 Exp", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v4-flash": { - id: "deepseek/deepseek-v4-flash", - name: "DeepSeek: DeepSeek V4 Flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.28, cache_read: 0.0028 }, - limit: { context: 1048576, output: 384000 }, - }, - "deepseek/deepseek-v4-pro": { - id: "deepseek/deepseek-v4-pro", - name: "DeepSeek: DeepSeek V4 Pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.435, output: 0.87, cache_read: 0.003625 }, - limit: { context: 1048576, output: 384000 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "DeepSeek: DeepSeek V3.2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 0.38, cache_read: 0.125 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-chat-v3-0324": { - id: "deepseek/deepseek-chat-v3-0324", - name: "DeepSeek: DeepSeek V3 0324", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-03-24", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.77, cache_read: 0.095 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-r1-0528": { - id: "deepseek/deepseek-r1-0528", - name: "DeepSeek: R1 0528", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.15, cache_read: 0.2 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek/deepseek-v3.1-terminus": { - id: "deepseek/deepseek-v3.1-terminus", - name: "DeepSeek: DeepSeek V3.1 Terminus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.21, output: 0.79, cache_read: 0.13 }, - limit: { context: 163840, output: 32768 }, - }, - "openrouter/auto": { - id: "openrouter/auto", - name: "Auto Router", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 2000000, output: 32768 }, - }, - "openrouter/bodybuilder": { - id: "openrouter/bodybuilder", - name: "Body Builder (beta)", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - status: "beta", - }, - "openrouter/owl-alpha": { - id: "openrouter/owl-alpha", - name: "Owl Alpha", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1048756, output: 262144 }, - status: "alpha", - }, - "openrouter/pareto-code": { - id: "openrouter/pareto-code", - name: "Pareto Code Router", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2026-04-21", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 65536 }, - }, - "openrouter/free": { - id: "openrouter/free", - name: "Free Models Router", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 32768 }, - }, - "inclusionai/ling-2.6-1t:free": { - id: "inclusionai/ling-2.6-1t:free", - name: "inclusionAI: Ling-2.6-1T (free)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-23", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "inclusionai/ling-2.6-flash": { - id: "inclusionai/ling-2.6-flash", - name: "inclusionAI: Ling-2.6 Flash", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.24, cache_read: 0.016 }, - limit: { context: 262144, output: 32768 }, - }, - "arcee-ai/trinity-mini": { - id: "arcee-ai/trinity-mini", - name: "Arcee AI: Trinity Mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12", - last_updated: "2026-01-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.045, output: 0.15 }, - limit: { context: 131072, output: 131072 }, - }, - "arcee-ai/virtuoso-large": { - id: "arcee-ai/virtuoso-large", - name: "Arcee AI: Virtuoso Large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-05-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 1.2 }, - limit: { context: 131072, output: 64000 }, - }, - "arcee-ai/trinity-large-thinking": { - id: "arcee-ai/trinity-large-thinking", - name: "Arcee AI: Trinity Large Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.85 }, - limit: { context: 262144, output: 262144 }, - }, - "arcee-ai/spotlight": { - id: "arcee-ai/spotlight", - name: "Arcee AI: Spotlight", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-05-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 131072, output: 65537 }, - }, - "arcee-ai/maestro-reasoning": { - id: "arcee-ai/maestro-reasoning", - name: "Arcee AI: Maestro Reasoning", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-05-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 3.3 }, - limit: { context: 131072, output: 32000 }, - }, - "arcee-ai/coder-large": { - id: "arcee-ai/coder-large", - name: "Arcee AI: Coder Large", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-05-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 0.8 }, - limit: { context: 32768, output: 32768 }, - }, - "arcee-ai/trinity-large-preview": { - id: "arcee-ai/trinity-large-preview", - name: "Arcee AI: Trinity Large Preview", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-01-28", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.45 }, - limit: { context: 131000, output: 32768 }, - }, - "deepcogito/cogito-v2.1-671b": { - id: "deepcogito/cogito-v2.1-671b", - name: "Deep Cogito: Cogito v2.1 671B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.25, output: 1.25 }, - limit: { context: 128000, output: 32768 }, - }, - "upstage/solar-pro-3": { - id: "upstage/solar-pro-3", - name: "Upstage: Solar Pro 3", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 32768 }, - }, - "nex-agi/deepseek-v3.1-nex-n1": { - id: "nex-agi/deepseek-v3.1-nex-n1", - name: "Nex AGI: DeepSeek V3.1 Nex N1", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 131072, output: 163840 }, - }, - "bytedance-seed/seed-1.6": { - id: "bytedance-seed/seed-1.6", - name: "ByteDance Seed: Seed 1.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 262144, output: 32768 }, - }, - "bytedance-seed/seed-2.0-lite": { - id: "bytedance-seed/seed-2.0-lite", - name: "ByteDance Seed: Seed-2.0-Lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-10", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2 }, - limit: { context: 262144, output: 131072 }, - }, - "bytedance-seed/seed-1.6-flash": { - id: "bytedance-seed/seed-1.6-flash", - name: "ByteDance Seed: Seed 1.6 Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 262144, output: 32768 }, - }, - "bytedance-seed/seed-2.0-mini": { - id: "bytedance-seed/seed-2.0-mini", - name: "ByteDance Seed: Seed-2.0-Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-27", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 262144, output: 131072 }, - }, - "mancer/weaver": { - id: "mancer/weaver", - name: "Mancer: Weaver (alpha)", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2023-08-02", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 1 }, - limit: { context: 8000, output: 2000 }, - }, - "anthracite-org/magnum-v4-72b": { - id: "anthracite-org/magnum-v4-72b", - name: "Magnum v4 72B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-10-22", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 5 }, - limit: { context: 16384, output: 2048 }, - }, - "~google/gemini-pro-latest": { - id: "~google/gemini-pro-latest", - name: "Google: Gemini Pro Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, cache_write: 0.375 }, - limit: { context: 1048576, output: 65536 }, - }, - "~google/gemini-flash-latest": { - id: "~google/gemini-flash-latest", - name: "Google: Gemini Flash Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05, cache_write: 0.08333333333333334 }, - limit: { context: 1048576, output: 65536 }, - }, - "kilo-auto/balanced": { - id: "kilo-auto/balanced", - name: "Kilo Auto Balanced", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3 }, - limit: { context: 204800, output: 131072 }, - }, - "kilo-auto/frontier": { - id: "kilo-auto/frontier", - name: "Kilo Auto Frontier", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25 }, - limit: { context: 1000000, output: 128000 }, - }, - "kilo-auto/small": { - id: "kilo-auto/small", - name: "Kilo Auto Small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 400000, output: 128000 }, - }, - "kilo-auto/free": { - id: "kilo-auto/free", - name: "Kilo Auto Free", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "undi95/remm-slerp-l2-13b": { - id: "undi95/remm-slerp-l2-13b", - name: "ReMM SLERP 13B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2023-07-22", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 0.65 }, - limit: { context: 6144, output: 4096 }, - }, - "allenai/olmo-3-32b-think": { - id: "allenai/olmo-3-32b-think", - name: "AllenAI: Olmo 3 32B Think", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-11-22", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.5 }, - limit: { context: 65536, output: 65536 }, - }, - "nousresearch/hermes-2-pro-llama-3-8b": { - id: "nousresearch/hermes-2-pro-llama-3-8b", - name: "NousResearch: Hermes 2 Pro - Llama-3 8B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-05-27", - last_updated: "2024-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.14 }, - limit: { context: 8192, output: 8192 }, - }, - "nousresearch/hermes-4-405b": { - id: "nousresearch/hermes-4-405b", - name: "Nous: Hermes 4 405B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-08-25", - last_updated: "2025-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 131072, output: 26215 }, - }, - "nousresearch/hermes-3-llama-3.1-70b": { - id: "nousresearch/hermes-3-llama-3.1-70b", - name: "Nous: Hermes 3 70B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-08-18", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 131072, output: 32768 }, - }, - "nousresearch/hermes-4-70b": { - id: "nousresearch/hermes-4-70b", - name: "Nous: Hermes 4 70B", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-08-25", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4, cache_read: 0.055 }, - limit: { context: 131072, output: 131072 }, - }, - "nousresearch/hermes-3-llama-3.1-405b": { - id: "nousresearch/hermes-3-llama-3.1-405b", - name: "Nous: Hermes 3 405B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-08-16", - last_updated: "2024-08-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 1 }, - limit: { context: 131072, output: 16384 }, - }, - "morph/morph-v3-fast": { - id: "morph/morph-v3-fast", - name: "Morph: Morph V3 Fast", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 1.2 }, - limit: { context: 81920, output: 38000 }, - }, - "morph/morph-v3-large": { - id: "morph/morph-v3-large", - name: "Morph: Morph V3 Large", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9, output: 1.9 }, - limit: { context: 262144, output: 131072 }, - }, - "stepfun/step-3.5-flash:free": { - id: "stepfun/step-3.5-flash:free", - name: "StepFun: Step 3.5 Flash (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-26", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "stepfun/step-3.5-flash": { - id: "stepfun/step-3.5-flash", - name: "StepFun: Step 3.5 Flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.02 }, - limit: { context: 256000, output: 256000 }, - }, - "alpindale/goliath-120b": { - id: "alpindale/goliath-120b", - name: "Goliath 120B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2023-11-10", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3.75, output: 7.5 }, - limit: { context: 6144, output: 1024 }, - }, - "mistralai/mistral-nemo": { - id: "mistralai/mistral-nemo", - name: "Mistral: Mistral Nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-01", - last_updated: "2024-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04 }, - limit: { context: 131072, output: 16384 }, - }, - "mistralai/mistral-saba": { - id: "mistralai/mistral-saba", - name: "Mistral: Saba", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-02-17", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 32768, output: 32768 }, - }, - "mistralai/mistral-large-2512": { - id: "mistralai/mistral-large-2512", - name: "Mistral: Mistral Large 3 2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-01", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 262144, output: 52429 }, - }, - "mistralai/devstral-medium": { - id: "mistralai/devstral-medium", - name: "Mistral: Devstral Medium", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 26215 }, - }, - "mistralai/mistral-small-3.1-24b-instruct": { - id: "mistralai/mistral-small-3.1-24b-instruct", - name: "Mistral: Mistral Small 3.1 24B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-17", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 0.56, cache_read: 0.015 }, - limit: { context: 128000, output: 131072 }, - }, - "mistralai/mistral-medium-3-5": { - id: "mistralai/mistral-medium-3-5", - name: "Mistral: Mistral Medium 3.5", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-30", - last_updated: "2026-05-07", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 7.5 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/pixtral-large-2411": { - id: "mistralai/pixtral-large-2411", - name: "Mistral: Pixtral Large 2411", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-19", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 131072, output: 32768 }, - }, - "mistralai/devstral-2512": { - id: "mistralai/devstral-2512", - name: "Mistral: Devstral 2 2512", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-12", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2, cache_read: 0.025 }, - limit: { context: 262144, output: 65536 }, - }, - "mistralai/codestral-2508": { - id: "mistralai/codestral-2508", - name: "Mistral: Codestral 2508", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 51200 }, - }, - "mistralai/mistral-small-24b-instruct-2501": { - id: "mistralai/mistral-small-24b-instruct-2501", - name: "Mistral: Mistral Small 3", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-29", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.08 }, - limit: { context: 32768, output: 16384 }, - }, - "mistralai/mistral-large-2411": { - id: "mistralai/mistral-large-2411", - name: "Mistral Large 2411", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-24", - last_updated: "2024-11-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 131072, output: 26215 }, - }, - "mistralai/mixtral-8x22b-instruct": { - id: "mistralai/mixtral-8x22b-instruct", - name: "Mistral: Mixtral 8x22B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-04-17", - last_updated: "2024-04-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 65536, output: 13108 }, - }, - "mistralai/mistral-large-2407": { - id: "mistralai/mistral-large-2407", - name: "Mistral Large 2407", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-19", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 131072, output: 32768 }, - }, - "mistralai/ministral-8b-2512": { - id: "mistralai/ministral-8b-2512", - name: "Mistral: Ministral 3 8B 2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 262144, output: 32768 }, - }, - "mistralai/mistral-medium-3.1": { - id: "mistralai/mistral-medium-3.1", - name: "Mistral: Mistral Medium 3.1", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 26215 }, - }, - "mistralai/mistral-small-2603": { - id: "mistralai/mistral-small-2603", - name: "Mistral: Mistral Small 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-04-11", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6, cache_read: 0.015 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/ministral-3b-2512": { - id: "mistralai/ministral-3b-2512", - name: "Mistral: Ministral 3 3B 2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 32768 }, - }, - "mistralai/voxtral-small-24b-2507": { - id: "mistralai/voxtral-small-24b-2507", - name: "Mistral: Voxtral Small 24B 2507", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 32000, output: 6400 }, - }, - "mistralai/mixtral-8x7b-instruct": { - id: "mistralai/mixtral-8x7b-instruct", - name: "Mistral: Mixtral 8x7B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-12-10", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.54, output: 0.54 }, - limit: { context: 32768, output: 16384 }, - }, - "mistralai/mistral-medium-3": { - id: "mistralai/mistral-medium-3", - name: "Mistral: Mistral Medium 3", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 26215 }, - }, - "mistralai/mistral-small-3.2-24b-instruct": { - id: "mistralai/mistral-small-3.2-24b-instruct", - name: "Mistral: Mistral Small 3.2 24B", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-20", - last_updated: "2025-06-20", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.18, cache_read: 0.03 }, - limit: { context: 131072, output: 131072 }, - }, - "mistralai/devstral-small": { - id: "mistralai/devstral-small", - name: "Mistral: Devstral Small 1.1", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-05-07", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 131072, output: 26215 }, - }, - "mistralai/mistral-large": { - id: "mistralai/mistral-large", - name: "Mistral Large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-24", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 25600 }, - }, - "mistralai/mistral-7b-instruct-v0.1": { - id: "mistralai/mistral-7b-instruct-v0.1", - name: "Mistral: Mistral 7B Instruct v0.1", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.11, output: 0.19 }, - limit: { context: 2824, output: 565 }, - }, - "mistralai/ministral-14b-2512": { - id: "mistralai/ministral-14b-2512", - name: "Mistral: Ministral 3 14B 2512", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 262144, output: 52429 }, - }, - "~anthropic/claude-haiku-latest": { - id: "~anthropic/claude-haiku-latest", - name: "Anthropic: Claude Haiku Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "~anthropic/claude-sonnet-latest": { - id: "~anthropic/claude-sonnet-latest", - name: "Anthropic: Claude Sonnet Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 128000 }, - }, - "~anthropic/claude-opus-latest": { - id: "~anthropic/claude-opus-latest", - name: "Anthropic: Claude Opus Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-16", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "meta-llama/llama-3.3-70b-instruct": { - id: "meta-llama/llama-3.3-70b-instruct", - name: "Meta: Llama 3.3 70B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-08-01", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.32 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/llama-4-scout": { - id: "meta-llama/llama-4-scout", - name: "Meta: Llama 4 Scout", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.3 }, - limit: { context: 327680, output: 16384 }, - }, - "meta-llama/llama-guard-3-8b": { - id: "meta-llama/llama-guard-3-8b", - name: "Llama Guard 3 8B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-18", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.06 }, - limit: { context: 131072, output: 26215 }, - }, - "meta-llama/llama-4-maverick": { - id: "meta-llama/llama-4-maverick", - name: "Meta: Llama 4 Maverick", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-12-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 1048576, output: 16384 }, - }, - "meta-llama/llama-3.2-11b-vision-instruct": { - id: "meta-llama/llama-3.2-11b-vision-instruct", - name: "Meta: Llama 3.2 11B Vision Instruct", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.049, output: 0.049 }, - limit: { context: 131072, output: 16384 }, - }, - "meta-llama/llama-guard-4-12b": { - id: "meta-llama/llama-guard-4-12b", - name: "Meta: Llama Guard 4 12B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 163840, output: 32768 }, - }, - "meta-llama/llama-3.1-70b-instruct": { - id: "meta-llama/llama-3.1-70b-instruct", - name: "Meta: Llama 3.1 70B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-16", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 131072, output: 26215 }, - }, - "meta-llama/llama-3.2-1b-instruct": { - id: "meta-llama/llama-3.2-1b-instruct", - name: "Meta: Llama 3.2 1B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-09-18", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.027, output: 0.2 }, - limit: { context: 60000, output: 12000 }, - }, - "meta-llama/llama-3.2-3b-instruct": { - id: "meta-llama/llama-3.2-3b-instruct", - name: "Meta: Llama 3.2 3B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-09-18", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.051, output: 0.34 }, - limit: { context: 80000, output: 16384 }, - }, - "meta-llama/llama-3-8b-instruct": { - id: "meta-llama/llama-3-8b-instruct", - name: "Meta: Llama 3 8B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-04-25", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.04 }, - limit: { context: 8192, output: 16384 }, - }, - "meta-llama/llama-3.1-8b-instruct": { - id: "meta-llama/llama-3.1-8b-instruct", - name: "Meta: Llama 3.1 8B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.05 }, - limit: { context: 16384, output: 16384 }, - }, - "meta-llama/llama-3-70b-instruct": { - id: "meta-llama/llama-3-70b-instruct", - name: "Meta: Llama 3 70B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.51, output: 0.74 }, - limit: { context: 8192, output: 8000 }, - }, - "x-ai/grok-4.20": { - id: "x-ai/grok-4.20", - name: "xAI: Grok 4.20", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-31", - last_updated: "2026-04-11", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2 }, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-code-fast-1:optimized:free": { - id: "x-ai/grok-code-fast-1:optimized:free", - name: "xAI: Grok Code Fast 1 Optimized (experimental, free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-27", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 10000 }, - }, - "x-ai/grok-4.3": { - id: "x-ai/grok-4.3", - name: "xAI: Grok 4.3", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-05-01", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 2.5, cache_read: 0.2 }, - limit: { context: 1000000, output: 4096 }, - }, - "x-ai/grok-4-fast": { - id: "x-ai/grok-4-fast", - name: "xAI: Grok 4 Fast", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "x-ai/grok-code-fast-1": { - id: "x-ai/grok-code-fast-1", - name: "xAI: Grok Code Fast 1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "x-ai/grok-3-beta": { - id: "x-ai/grok-3-beta", - name: "xAI: Grok 3 Beta", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 26215 }, - }, - "x-ai/grok-4": { - id: "x-ai/grok-4", - name: "xAI: Grok 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 51200 }, - }, - "x-ai/grok-3-mini": { - id: "x-ai/grok-3-mini", - name: "xAI: Grok 3 Mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 26215 }, - }, - "x-ai/grok-4.1-fast": { - id: "x-ai/grok-4.1-fast", - name: "xAI: Grok 4.1 Fast", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "x-ai/grok-3-mini-beta": { - id: "x-ai/grok-3-mini-beta", - name: "xAI: Grok 3 Mini Beta", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 26215 }, - }, - "x-ai/grok-4.20-multi-agent": { - id: "x-ai/grok-4.20-multi-agent", - name: "xAI: Grok 4.20 Multi-Agent", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-31", - last_updated: "2026-04-11", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2 }, - limit: { context: 2000000, output: 2000000 }, - }, - "x-ai/grok-3": { - id: "x-ai/grok-3", - name: "xAI: Grok 3", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 26215 }, - }, - "tencent/hy3-preview:free": { - id: "tencent/hy3-preview:free", - name: "Tencent: Hy3 Preview (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "tencent/hunyuan-a13b-instruct": { - id: "tencent/hunyuan-a13b-instruct", - name: "Tencent: Hunyuan A13B Instruct", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131072, output: 131072 }, - }, - "gryphe/mythomax-l2-13b": { - id: "gryphe/mythomax-l2-13b", - name: "MythoMax 13B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-25", - last_updated: "2024-04-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.06 }, - limit: { context: 4096, output: 4096 }, - }, - "sao10k/l3-euryale-70b": { - id: "sao10k/l3-euryale-70b", - name: "Sao10k: Llama 3 Euryale 70B v2.1", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-06-18", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.48, output: 1.48 }, - limit: { context: 8192, output: 8192 }, - }, - "sao10k/l3-lunaris-8b": { - id: "sao10k/l3-lunaris-8b", - name: "Sao10K: Llama 3 8B Lunaris", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-08-13", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.05 }, - limit: { context: 8192, output: 8192 }, - }, - "sao10k/l3.3-euryale-70b": { - id: "sao10k/l3.3-euryale-70b", - name: "Sao10K: Llama 3.3 Euryale 70B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-12-18", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 0.75 }, - limit: { context: 131072, output: 16384 }, - }, - "sao10k/l3.1-70b-hanami-x1": { - id: "sao10k/l3.1-70b-hanami-x1", - name: "Sao10K: Llama 3.1 70B Hanami x1", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-01-08", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 3 }, - limit: { context: 16000, output: 16000 }, - }, - "sao10k/l3.1-euryale-70b": { - id: "sao10k/l3.1-euryale-70b", - name: "Sao10K: Llama 3.1 Euryale 70B v2.2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-08-28", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.85, output: 0.85 }, - limit: { context: 131072, output: 16384 }, - }, - "microsoft/wizardlm-2-8x22b": { - id: "microsoft/wizardlm-2-8x22b", - name: "WizardLM-2 8x22B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-04-24", - last_updated: "2024-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.62, output: 0.62 }, - limit: { context: 65535, output: 8000 }, - }, - "microsoft/phi-4-mini-instruct": { - id: "microsoft/phi-4-mini-instruct", - name: "Microsoft: Phi 4 Mini Instruct", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-10-17", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.35, cache_read: 0.08 }, - limit: { context: 128000, output: 128000 }, - }, - "microsoft/phi-4": { - id: "microsoft/phi-4", - name: "Microsoft: Phi 4", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.14 }, - limit: { context: 16384, output: 16384 }, - }, - "poolside/laguna-m.1:free": { - id: "poolside/laguna-m.1:free", - name: "Poolside: Laguna M.1 (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "poolside/laguna-xs.2:free": { - id: "poolside/laguna-xs.2:free", - name: "Poolside: Laguna XS.2 (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "cohere/command-r7b-12-2024": { - id: "cohere/command-r7b-12-2024", - name: "Cohere: Command R7B (12-2024)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-02-27", - last_updated: "2024-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0375, output: 0.15 }, - limit: { context: 128000, output: 4000 }, - }, - "cohere/command-a": { - id: "cohere/command-a", - name: "Cohere: Command A", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 8192 }, - }, - "cohere/command-r-plus-08-2024": { - id: "cohere/command-r-plus-08-2024", - name: "Cohere: Command R+ (08-2024)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 4000 }, - }, - "cohere/command-r-08-2024": { - id: "cohere/command-r-08-2024", - name: "Cohere: Command R (08-2024)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4000 }, - }, - "prime-intellect/intellect-3": { - id: "prime-intellect/intellect-3", - name: "Prime Intellect: INTELLECT-3", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-11-26", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/llama-3.3-nemotron-super-49b-v1.5": { - id: "nvidia/llama-3.3-nemotron-super-49b-v1.5", - name: "NVIDIA: Llama 3.3 Nemotron Super 49B V1.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-03-16", - last_updated: "2025-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 131072, output: 26215 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "NVIDIA: Nemotron 3 Super", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free": { - id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", - name: "NVIDIA: Nemotron 3 Nano Omni (free)", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-05-01", - modalities: { input: ["text", "audio", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 65536 }, - }, - "nvidia/nemotron-3-nano-30b-a3b": { - id: "nvidia/nemotron-3-nano-30b-a3b", - name: "NVIDIA: Nemotron 3 Nano 30B A3B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-12", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.2 }, - limit: { context: 262144, output: 52429 }, - }, - "nvidia/nemotron-3-super-120b-a12b:free": { - id: "nvidia/nemotron-3-super-120b-a12b:free", - name: "NVIDIA: Nemotron 3 Super (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-12", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/nemotron-nano-9b-v2": { - id: "nvidia/nemotron-nano-9b-v2", - name: "NVIDIA: Nemotron Nano 9B V2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-18", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.16 }, - limit: { context: 131072, output: 26215 }, - }, - "nvidia/llama-3.1-nemotron-70b-instruct": { - id: "nvidia/llama-3.1-nemotron-70b-instruct", - name: "NVIDIA: Llama 3.1 Nemotron 70B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-10-12", - last_updated: "2024-10-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 1.2 }, - limit: { context: 131072, output: 16384 }, - }, - "inception/mercury-2": { - id: "inception/mercury-2", - name: "Inception: Mercury 2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 50000 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "OpenAI: GPT-5.1-Codex-Max", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-chat": { - id: "openai/gpt-5.2-chat", - name: "OpenAI: GPT-5.2 Chat", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4o-mini-search-preview": { - id: "openai/gpt-4o-mini-search-preview", - name: "OpenAI: GPT-4o-mini Search Preview", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5-chat": { - id: "openai/gpt-5-chat", - name: "OpenAI: GPT-5 Chat", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-08-07", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4o-2024-05-13": { - id: "openai/gpt-4o-2024-05-13", - name: "OpenAI: GPT-4o (2024-05-13)", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-05-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 15 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-5.3-chat": { - id: "openai/gpt-5.3-chat", - name: "OpenAI: GPT-5.3 Chat", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2026-03-04", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "OpenAI: GPT-5.2 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4-1106-preview": { - id: "openai/gpt-4-1106-preview", - name: "OpenAI: GPT-4 Turbo (older v1106)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-11-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-chat-latest": { - id: "openai/gpt-chat-latest", - name: "OpenAI: GPT Chat Latest", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - release_date: "2026-05-05", - last_updated: "2026-05-07", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4o-audio-preview": { - id: "openai/gpt-4o-audio-preview", - name: "OpenAI: GPT-4o Audio", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-15", - last_updated: "2026-03-15", - modalities: { input: ["audio", "text"], output: ["audio", "text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "OpenAI: GPT-5.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-24", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 1050000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "OpenAI: GPT-5 Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-07", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "OpenAI: GPT-5 Nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-07", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "OpenAI: GPT-5.3-Codex", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-02-25", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-3.5-turbo-16k": { - id: "openai/gpt-3.5-turbo-16k", - name: "OpenAI: GPT-3.5 Turbo 16k", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-08-28", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 4 }, - limit: { context: 16385, output: 4096 }, - }, - "openai/gpt-4-turbo": { - id: "openai/gpt-4-turbo", - name: "OpenAI: GPT-4 Turbo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-09-13", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "OpenAI: GPT-5.2", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/o3-pro": { - id: "openai/o3-pro", - name: "OpenAI: o3 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-16", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 80 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3-mini-high": { - id: "openai/o3-mini-high", - name: "OpenAI: o3 Mini High", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-01-31", - last_updated: "2026-03-15", - modalities: { input: ["pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "OpenAI: GPT-4o-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-18", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.075 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini-deep-research": { - id: "openai/o4-mini-deep-research", - name: "OpenAI: o4 Mini Deep Research", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-06-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-mini": { - id: "openai/gpt-5.4-mini", - name: "OpenAI: GPT-5.4 Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-17", - last_updated: "2026-04-11", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1-chat": { - id: "openai/gpt-5.1-chat", - name: "OpenAI: GPT-5.1 Chat", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-11-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "OpenAI: o4 Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-16", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.275 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-nano": { - id: "openai/gpt-5.4-nano", - name: "OpenAI: GPT-5.4 Nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-17", - last_updated: "2026-04-11", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "OpenAI: GPT-5.2-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4o-mini-2024-07-18": { - id: "openai/gpt-4o-mini-2024-07-18", - name: "OpenAI: GPT-4o-mini (2024-07-18)", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-18", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "OpenAI: GPT-5.1-Codex-Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 100000 }, - }, - "openai/gpt-4o-2024-08-06": { - id: "openai/gpt-4o-2024-08-06", - name: "OpenAI: GPT-4o (2024-08-06)", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-08-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5-image": { - id: "openai/gpt-5-image", - name: "OpenAI: GPT-5 Image", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-14", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 10, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "OpenAI: GPT-5.1", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/o1": { - id: "openai/o1", - name: "OpenAI: o1", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-12-05", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "OpenAI: GPT-5.4 Pro", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-03-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 1050000, output: 128000 }, - }, - "openai/gpt-3.5-turbo": { - id: "openai/gpt-3.5-turbo", - name: "OpenAI: GPT-3.5 Turbo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-03-01", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 16385, output: 4096 }, - }, - "openai/o3-deep-research": { - id: "openai/o3-deep-research", - name: "OpenAI: o3 Deep Research", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-06-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 40, cache_read: 2.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "OpenAI: o3 Mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-12-20", - last_updated: "2026-03-15", - modalities: { input: ["pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4-turbo-preview": { - id: "openai/gpt-4-turbo-preview", - name: "OpenAI: GPT-4 Turbo Preview", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-01-25", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/o1-pro": { - id: "openai/o1-pro", - name: "OpenAI: o1-pro", - attachment: true, - reasoning: true, - tool_call: false, - temperature: false, - release_date: "2025-03-19", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 150, output: 600 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-image-2": { - id: "openai/gpt-5.4-image-2", - name: "OpenAI: GPT-5.4 Image 2", - attachment: true, - reasoning: true, - tool_call: false, - temperature: false, - release_date: "2026-04-21", - last_updated: "2026-05-01", - modalities: { input: ["image", "text", "pdf"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 8, output: 15, cache_read: 2 }, - limit: { context: 272000, output: 128000 }, - }, - "openai/gpt-4": { - id: "openai/gpt-4", - name: "OpenAI: GPT-4", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-03-14", - last_updated: "2024-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 60 }, - limit: { context: 8191, output: 4096 }, - }, - "openai/gpt-4-0314": { - id: "openai/gpt-4-0314", - name: "OpenAI: GPT-4 (older v0314)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-05-28", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 60 }, - limit: { context: 8191, output: 4096 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "OpenAI: GPT-5 Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "OpenAI: GPT-5.4", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-03-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15 }, - limit: { context: 1050000, output: 128000 }, - }, - "openai/gpt-audio": { - id: "openai/gpt-audio", - name: "OpenAI: GPT Audio", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-20", - last_updated: "2026-03-15", - modalities: { input: ["audio", "text"], output: ["audio", "text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4o-search-preview": { - id: "openai/gpt-4o-search-preview", - name: "OpenAI: GPT-4o Search Preview", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-03-13", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4.1-nano": { - id: "openai/gpt-4.1-nano", - name: "OpenAI: GPT-4.1 Nano", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-14", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/o4-mini-high": { - id: "openai/o4-mini-high", - name: "OpenAI: o4 Mini High", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2025-04-17", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3": { - id: "openai/o3", - name: "OpenAI: o3", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-16", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "OpenAI: gpt-oss-20b", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.14 }, - limit: { context: 131072, output: 26215 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "OpenAI: GPT-5 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-10-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-audio-mini": { - id: "openai/gpt-audio-mini", - name: "OpenAI: GPT Audio Mini", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-20", - last_updated: "2026-03-15", - modalities: { input: ["audio", "text"], output: ["audio", "text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.4 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "OpenAI: GPT-4o", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-05-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-3.5-turbo-0613": { - id: "openai/gpt-3.5-turbo-0613", - name: "OpenAI: GPT-3.5 Turbo (older v0613)", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2023-06-13", - last_updated: "2023-06-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2 }, - limit: { context: 4095, output: 4096 }, - }, - "openai/gpt-5-image-mini": { - id: "openai/gpt-5-image-mini", - name: "OpenAI: GPT-5 Image Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-16", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 2.5, output: 2 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "OpenAI: GPT-5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-07", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-safeguard-20b": { - id: "openai/gpt-oss-safeguard-20b", - name: "OpenAI: gpt-oss-safeguard-20b", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-29", - last_updated: "2025-10-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3, cache_read: 0.037 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "OpenAI: gpt-oss-120b", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.039, output: 0.19 }, - limit: { context: 131072, output: 26215 }, - }, - "openai/gpt-5.5-pro": { - id: "openai/gpt-5.5-pro", - name: "OpenAI: GPT-5.5 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-24", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 1050000, output: 128000 }, - }, - "openai/gpt-3.5-turbo-instruct": { - id: "openai/gpt-3.5-turbo-instruct", - name: "OpenAI: GPT-3.5 Turbo Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2023-03-01", - last_updated: "2023-09-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 4095, output: 4096 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "OpenAI: GPT-4.1", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-14", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "OpenAI: GPT-4.1 Mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-14", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "OpenAI: GPT-5.1-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4o-2024-11-20": { - id: "openai/gpt-4o-2024-11-20", - name: "OpenAI: GPT-4o (2024-11-20)", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-20", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "amazon/nova-lite-v1": { - id: "amazon/nova-lite-v1", - name: "Amazon: Nova Lite 1.0", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-06", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.24 }, - limit: { context: 300000, output: 5120 }, - }, - "amazon/nova-pro-v1": { - id: "amazon/nova-pro-v1", - name: "Amazon: Nova Pro 1.0", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2 }, - limit: { context: 300000, output: 5120 }, - }, - "amazon/nova-premier-v1": { - id: "amazon/nova-premier-v1", - name: "Amazon: Nova Premier 1.0", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-11-01", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 12.5 }, - limit: { context: 1000000, output: 32000 }, - }, - "amazon/nova-2-lite-v1": { - id: "amazon/nova-2-lite-v1", - name: "Amazon: Nova 2 Lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1000000, output: 65535 }, - }, - "amazon/nova-micro-v1": { - id: "amazon/nova-micro-v1", - name: "Amazon: Nova Micro 1.0", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.035, output: 0.14 }, - limit: { context: 128000, output: 5120 }, - }, - "z-ai/glm-5v-turbo": { - id: "z-ai/glm-5v-turbo", - name: "Z.ai: GLM 5V Turbo", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-11", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 4, cache_read: 0.24 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4.7": { - id: "z-ai/glm-4.7", - name: "Z.ai: GLM 4.7", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-22", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.38, output: 1.98, cache_read: 0.2 }, - limit: { context: 202752, output: 65535 }, - }, - "z-ai/glm-5": { - id: "z-ai/glm-5", - name: "Z.ai: GLM 5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.72, output: 2.3 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4-32b": { - id: "z-ai/glm-4-32b", - name: "Z.ai: GLM 4 32B ", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-25", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 32768 }, - }, - "z-ai/glm-5.1": { - id: "z-ai/glm-5.1", - name: "Z.ai: GLM 5.1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.26, output: 3.96 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4.5": { - id: "z-ai/glm-4.5", - name: "Z.ai: GLM 4.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.175 }, - limit: { context: 131072, output: 98304 }, - }, - "z-ai/glm-4.5-air": { - id: "z-ai/glm-4.5-air", - name: "Z.ai: GLM 4.5 Air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.85, cache_read: 0.025 }, - limit: { context: 131072, output: 98304 }, - }, - "z-ai/glm-5-turbo": { - id: "z-ai/glm-5-turbo", - name: "Z.ai: GLM 5 Turbo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 4, cache_read: 0.24 }, - limit: { context: 202752, output: 131072 }, - }, - "z-ai/glm-4.5v": { - id: "z-ai/glm-4.5v", - name: "Z.ai: GLM 4.5V", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8, cache_read: 0.11 }, - limit: { context: 65536, output: 16384 }, - }, - "z-ai/glm-4.6": { - id: "z-ai/glm-4.6", - name: "Z.ai: GLM 4.6", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-30", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.39, output: 1.9, cache_read: 0.175 }, - limit: { context: 204800, output: 204800 }, - }, - "z-ai/glm-4.6v": { - id: "z-ai/glm-4.6v", - name: "Z.ai: GLM 4.6V", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-30", - last_updated: "2026-01-10", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 131072, output: 131072 }, - }, - "z-ai/glm-4.7-flash": { - id: "z-ai/glm-4.7-flash", - name: "Z.ai: GLM 4.7 Flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4, cache_read: 0.01 }, - limit: { context: 202752, output: 40551 }, - }, - "baidu/ernie-4.5-vl-424b-a47b": { - id: "baidu/ernie-4.5-vl-424b-a47b", - name: "Baidu: ERNIE 4.5 VL 424B A47B ", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-06-30", - last_updated: "2026-01", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.42, output: 1.25 }, - limit: { context: 123000, output: 16000 }, - }, - "baidu/qianfan-ocr-fast:free": { - id: "baidu/qianfan-ocr-fast:free", - name: "Baidu: Qianfan-OCR-Fast (free)", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-05-01", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 65536, output: 28672 }, - }, - "baidu/cobuddy:free": { - id: "baidu/cobuddy:free", - name: "Baidu: CoBuddy (free)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-05-06", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 65536 }, - }, - "baidu/ernie-4.5-vl-28b-a3b": { - id: "baidu/ernie-4.5-vl-28b-a3b", - name: "Baidu: ERNIE 4.5 VL 28B A3B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.56 }, - limit: { context: 30000, output: 8000 }, - }, - "baidu/ernie-4.5-21b-a3b": { - id: "baidu/ernie-4.5-21b-a3b", - name: "Baidu: ERNIE 4.5 21B A3B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-06-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 120000, output: 8000 }, - }, - "baidu/ernie-4.5-300b-a47b": { - id: "baidu/ernie-4.5-300b-a47b", - name: "Baidu: ERNIE 4.5 300B A47B ", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-06-30", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 123000, output: 12000 }, - }, - "baidu/ernie-4.5-21b-a3b-thinking": { - id: "baidu/ernie-4.5-21b-a3b-thinking", - name: "Baidu: ERNIE 4.5 21B A3B Thinking", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131072, output: 65536 }, - }, - "relace/relace-apply-3": { - id: "relace/relace-apply-3", - name: "Relace: Relace Apply 3", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-09-26", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.85, output: 1.25 }, - limit: { context: 256000, output: 128000 }, - }, - "relace/relace-search": { - id: "relace/relace-search", - name: "Relace: Relace Search", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-09", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3 }, - limit: { context: 256000, output: 128000 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "MiniMax: MiniMax M2.7", - family: "minimax-m2.7", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "MiniMax: MiniMax M2", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-23", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.255, output: 1, cache_read: 0.03 }, - limit: { context: 196608, output: 196608 }, - }, - "minimax/minimax-01": { - id: "minimax/minimax-01", - name: "MiniMax: MiniMax-01", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 1000192, output: 1000192 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "MiniMax: MiniMax M2.1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.95, cache_read: 0.03 }, - limit: { context: 196608, output: 39322 }, - }, - "minimax/minimax-m1": { - id: "minimax/minimax-m1", - name: "MiniMax: MiniMax M1", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2.2 }, - limit: { context: 1000000, output: 40000 }, - }, - "minimax/minimax-m2-her": { - id: "minimax/minimax-m2-her", - name: "MiniMax: MiniMax M2-her", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-23", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 65536, output: 2048 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax: MiniMax M2.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1.2, cache_read: 0.029 }, - limit: { context: 196608, output: 196608 }, - }, - "~openai/gpt-latest": { - id: "~openai/gpt-latest", - name: "OpenAI: GPT Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 1050000, output: 128000 }, - }, - "~openai/gpt-mini-latest": { - id: "~openai/gpt-mini-latest", - name: "OpenAI: GPT Mini Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "qwen/qwen3-235b-a22b": { - id: "qwen/qwen3-235b-a22b", - name: "Qwen: Qwen3 235B A22B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.455, output: 1.82, cache_read: 0.15 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen/qwen3.5-122b-a10b": { - id: "qwen/qwen3.5-122b-a10b", - name: "Qwen: Qwen3.5-122B-A10B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 2.08 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-coder-plus": { - id: "qwen/qwen3-coder-plus", - name: "Qwen: Qwen3 Coder Plus", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 3.25, cache_read: 0.2 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3.6-27b": { - id: "qwen/qwen3.6-27b", - name: "Qwen: Qwen3.6 27B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.325, output: 3.25 }, - limit: { context: 256000, output: 65536 }, - }, - "qwen/qwen3.5-27b": { - id: "qwen/qwen3.5-27b", - name: "Qwen: Qwen3.5-27B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.195, output: 1.56 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-235b-a22b-2507": { - id: "qwen/qwen3-235b-a22b-2507", - name: "Qwen: Qwen3 235B A22B Instruct 2507", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04", - last_updated: "2026-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.071, output: 0.1 }, - limit: { context: 262144, output: 52429 }, - }, - "qwen/qwen3-8b": { - id: "qwen/qwen3-8b", - name: "Qwen: Qwen3 8B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.4, cache_read: 0.05 }, - limit: { context: 40960, output: 8192 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen: Qwen3.5 397B A17B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39, output: 2.34 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen-vl-plus": { - id: "qwen/qwen-vl-plus", - name: "Qwen: Qwen VL Plus", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-01-25", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1365, output: 0.4095, cache_read: 0.042 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen/qwen3-32b": { - id: "qwen/qwen3-32b", - name: "Qwen: Qwen3 32B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.24, cache_read: 0.04 }, - limit: { context: 40960, output: 40960 }, - }, - "qwen/qwen2.5-vl-72b-instruct": { - id: "qwen/qwen2.5-vl-72b-instruct", - name: "Qwen: Qwen2.5 VL 72B Instruct", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-02-01", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 0.8, cache_read: 0.075 }, - limit: { context: 32768, output: 32768 }, - }, - "qwen/qwen-max": { - id: "qwen/qwen-max", - name: "Qwen: Qwen-Max ", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-04-03", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.04, output: 4.16, cache_read: 0.32 }, - limit: { context: 32768, output: 8192 }, - }, - "qwen/qwen-plus": { - id: "qwen/qwen-plus", - name: "Qwen: Qwen-Plus", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-01-25", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.2, cache_read: 0.08 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen/qwen3.6-35b-a3b": { - id: "qwen/qwen3.6-35b-a3b", - name: "Qwen: Qwen3.6 35B A3B", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1612, output: 0.96525, cache_read: 0.1612 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-vl-235b-a22b-thinking": { - id: "qwen/qwen3-vl-235b-a22b-thinking", - name: "Qwen: Qwen3 VL 235B A22B Thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-24", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 2.6 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-vl-30b-a3b-thinking": { - id: "qwen/qwen3-vl-30b-a3b-thinking", - name: "Qwen: Qwen3 VL 30B A3B Thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-11", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 1.56 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-vl-8b-instruct": { - id: "qwen/qwen3-vl-8b-instruct", - name: "Qwen: Qwen3 VL 8B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.5 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3.5-flash-02-23": { - id: "qwen/qwen3.5-flash-02-23", - name: "Qwen: Qwen3.5-Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3.6-plus": { - id: "qwen/qwen3.6-plus", - name: "Qwen: Qwen3.6 Plus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-26", - last_updated: "2026-04-11", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.325, output: 1.95, cache_read: 0.0325, cache_write: 0.40625 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3-max": { - id: "qwen/qwen3-max", - name: "Qwen: Qwen3 Max", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-05", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6, cache_read: 0.24 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen/qwen-plus-2025-07-28": { - id: "qwen/qwen-plus-2025-07-28", - name: "Qwen: Qwen Plus 0728", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-09", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 0.78 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen/qwen3-30b-a3b-instruct-2507": { - id: "qwen/qwen3-30b-a3b-instruct-2507", - name: "Qwen: Qwen3 30B A3B Instruct 2507", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-29", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.3, cache_read: 0.04 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3-vl-32b-instruct": { - id: "qwen/qwen3-vl-32b-instruct", - name: "Qwen: Qwen3 VL 32B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-10-21", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.104, output: 0.416 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-235b-a22b-thinking-2507": { - id: "qwen/qwen3-235b-a22b-thinking-2507", - name: "Qwen: Qwen3 235B A22B Thinking 2507", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-25", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3-next-80b-a3b-thinking": { - id: "qwen/qwen3-next-80b-a3b-thinking", - name: "Qwen: Qwen3 Next 80B A3B Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0975, output: 0.78 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-30b-a3b-thinking-2507": { - id: "qwen/qwen3-30b-a3b-thinking-2507", - name: "Qwen: Qwen3 30B A3B Thinking 2507", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.051, output: 0.34 }, - limit: { context: 32768, output: 6554 }, - }, - "qwen/qwen-2.5-7b-instruct": { - id: "qwen/qwen-2.5-7b-instruct", - name: "Qwen: Qwen2.5 7B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.1 }, - limit: { context: 32768, output: 6554 }, - }, - "qwen/qwen-vl-max": { - id: "qwen/qwen-vl-max", - name: "Qwen: Qwen VL Max", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-04-08", - last_updated: "2025-08-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-coder-flash": { - id: "qwen/qwen3-coder-flash", - name: "Qwen: Qwen3 Coder Flash", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-23", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.195, output: 0.975, cache_read: 0.06 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3-30b-a3b": { - id: "qwen/qwen3-30b-a3b", - name: "Qwen: Qwen3 30B A3B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.28, cache_read: 0.03 }, - limit: { context: 40960, output: 40960 }, - }, - "qwen/qwen3-next-80b-a3b-instruct": { - id: "qwen/qwen3-next-80b-a3b-instruct", - name: "Qwen: Qwen3 Next 80B A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 1.1 }, - limit: { context: 131072, output: 52429 }, - }, - "qwen/qwen3.5-plus-20260420": { - id: "qwen/qwen3.5-plus-20260420", - name: "Qwen: Qwen3.5 Plus 2026-04-20", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3-coder-next": { - id: "qwen/qwen3-coder-next", - name: "Qwen: Qwen3 Coder Next", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-02-02", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.75, cache_read: 0.035 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen-2.5-coder-32b-instruct": { - id: "qwen/qwen-2.5-coder-32b-instruct", - name: "Qwen2.5 Coder 32B Instruct", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-11-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2, cache_read: 0.015 }, - limit: { context: 32768, output: 8192 }, - }, - "qwen/qwen3-vl-30b-a3b-instruct": { - id: "qwen/qwen3-vl-30b-a3b-instruct", - name: "Qwen: Qwen3 VL 30B A3B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-10-05", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-coder-30b-a3b-instruct": { - id: "qwen/qwen3-coder-30b-a3b-instruct", - name: "Qwen: Qwen3 Coder 30B A3B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.27 }, - limit: { context: 160000, output: 32768 }, - }, - "qwen/qwen3-max-thinking": { - id: "qwen/qwen3-max-thinking", - name: "Qwen: Qwen3 Max Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-23", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.78, output: 3.9 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen/qwen-turbo": { - id: "qwen/qwen-turbo", - name: "Qwen: Qwen-Turbo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-01", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0325, output: 0.13, cache_read: 0.01 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen/qwen3-vl-235b-a22b-instruct": { - id: "qwen/qwen3-vl-235b-a22b-instruct", - name: "Qwen: Qwen3 VL 235B A22B Instruct", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-23", - last_updated: "2026-01-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.88, cache_read: 0.11 }, - limit: { context: 262144, output: 52429 }, - }, - "qwen/qwen3-coder": { - id: "qwen/qwen3-coder", - name: "Qwen: Qwen3 Coder 480B A35B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 1, cache_read: 0.022 }, - limit: { context: 262144, output: 52429 }, - }, - "qwen/qwen3.5-9b": { - id: "qwen/qwen3.5-9b", - name: "Qwen: Qwen3.5-9B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-10", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.15 }, - limit: { context: 256000, output: 32768 }, - }, - "qwen/qwen3-vl-8b-thinking": { - id: "qwen/qwen3-vl-8b-thinking", - name: "Qwen: Qwen3 VL 8B Thinking", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.117, output: 1.365 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3.6-max-preview": { - id: "qwen/qwen3.6-max-preview", - name: "Qwen: Qwen3.6 Max Preview", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.04, output: 6.24, cache_write: 1.3 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen-plus-2025-07-28:thinking": { - id: "qwen/qwen-plus-2025-07-28:thinking", - name: "Qwen: Qwen Plus 0728 (thinking)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-09", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 0.78 }, - limit: { context: 1000000, output: 32768 }, - }, - "qwen/qwen-2.5-72b-instruct": { - id: "qwen/qwen-2.5-72b-instruct", - name: "Qwen2.5 72B Instruct", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.39 }, - limit: { context: 32768, output: 16384 }, - }, - "qwen/qwen3-14b": { - id: "qwen/qwen3-14b", - name: "Qwen: Qwen3 14B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.24, cache_read: 0.025 }, - limit: { context: 40960, output: 40960 }, - }, - "qwen/qwen3.5-35b-a3b": { - id: "qwen/qwen3.5-35b-a3b", - name: "Qwen: Qwen3.5-35B-A3B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1625, output: 1.3 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3.5-plus-02-15": { - id: "qwen/qwen3.5-plus-02-15", - name: "Qwen: Qwen3.5 Plus 2026-02-15", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-03-15", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.26, output: 1.56 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen/qwen3.6-flash": { - id: "qwen/qwen3.6-flash", - name: "Qwen: Qwen3.6 Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_write: 0.3125 }, - limit: { context: 1000000, output: 65536 }, - }, - "alfredpros/codellama-7b-instruct-solidity": { - id: "alfredpros/codellama-7b-instruct-solidity", - name: "AlfredPros: CodeLLaMa 7B Instruct Solidity", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-14", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 1.2 }, - limit: { context: 4096, output: 4096 }, - }, - "kwaipilot/kat-coder-pro-v2": { - id: "kwaipilot/kat-coder-pro-v2", - name: "Kwaipilot: KAT-Coder-Pro V2", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 256000, output: 80000 }, - }, - "google/gemini-2.5-pro-preview-05-06": { - id: "google/gemini-2.5-pro-preview-05-06", - name: "Google: Gemini 2.5 Pro Preview 05-06", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-06", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, reasoning: 10, cache_read: 0.125, cache_write: 0.375 }, - limit: { context: 1048576, output: 65535 }, - }, - "google/lyria-3-clip-preview": { - id: "google/lyria-3-clip-preview", - name: "Google: Lyria 3 Clip Preview", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-04-11", - modalities: { input: ["image", "text"], output: ["audio", "text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3.1-pro-preview-customtools": { - id: "google/gemini-3.1-pro-preview-customtools", - name: "Google: Gemini 3.1 Pro Preview Custom Tools", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, reasoning: 12 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-flash-lite-preview-09-2025": { - id: "google/gemini-2.5-flash-lite-preview-09-2025", - name: "Google: Gemini 2.5 Flash Lite Preview 09-2025", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-25", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, reasoning: 0.4, cache_read: 0.01, cache_write: 0.083333 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.0-flash-001": { - id: "google/gemini-2.0-flash-001", - name: "Google: Gemini 2.0 Flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-11", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025, cache_write: 0.083333 }, - limit: { context: 1048576, output: 8192 }, - }, - "google/lyria-3-pro-preview": { - id: "google/lyria-3-pro-preview", - name: "Google: Lyria 3 Pro Preview", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-04-11", - modalities: { input: ["image", "text"], output: ["audio", "text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-3n-e4b-it": { - id: "google/gemma-3n-e4b-it", - name: "Google: Gemma 3n 4B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04 }, - limit: { context: 32768, output: 6554 }, - }, - "google/gemini-3.1-flash-lite-preview": { - id: "google/gemini-3.1-flash-lite-preview", - name: "Google: Gemini 3.1 Flash Lite Preview", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-03", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, reasoning: 1.5 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3.1-pro-preview": { - id: "google/gemini-3.1-pro-preview", - name: "Google: Gemini 3.1 Pro Preview", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-19", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, reasoning: 12 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Google: Gemini 3 Flash Preview", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-17", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, reasoning: 3, cache_read: 0.05, cache_write: 0.083333 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Google: Gemini 2.5 Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-03-20", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, reasoning: 10, cache_read: 0.125, cache_write: 0.375 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-pro-image-preview": { - id: "google/gemini-3-pro-image-preview", - name: "Google: Nano Banana Pro (Gemini 3 Pro Image Preview)", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-11-20", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 2, output: 12, reasoning: 12 }, - limit: { context: 65536, output: 32768 }, - }, - "google/gemma-4-31b-it": { - id: "google/gemma-4-31b-it", - name: "Google: Gemma 4 31B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-11", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.4 }, - limit: { context: 262144, output: 131072 }, - }, - "google/gemini-2.5-flash-image": { - id: "google/gemini-2.5-flash-image", - name: "Google: Nano Banana (Gemini 2.5 Flash Image)", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-08", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 32768, output: 32768 }, - }, - "google/gemma-3-12b-it": { - id: "google/gemma-3-12b-it", - name: "Google: Gemma 3 12B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.13, cache_read: 0.015 }, - limit: { context: 131072, output: 131072 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Google: Gemini 2.5 Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-17", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, reasoning: 2.5, cache_read: 0.03, cache_write: 0.083333 }, - limit: { context: 1048576, output: 65535 }, - }, - "google/gemini-3.1-flash-image-preview": { - id: "google/gemini-3.1-flash-image-preview", - name: "Google: Nano Banana 2 (Gemini 3.1 Flash Image Preview)", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["image", "text"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 65536, output: 65536 }, - }, - "google/gemma-3-4b-it": { - id: "google/gemma-3-4b-it", - name: "Google: Gemma 3 4B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-13", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.08 }, - limit: { context: 131072, output: 19200 }, - }, - "google/gemini-2.5-pro-preview": { - id: "google/gemini-2.5-pro-preview", - name: "Google: Gemini 2.5 Pro Preview 06-05", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-05", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, reasoning: 10, cache_read: 0.125, cache_write: 0.375 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemma-2-27b-it": { - id: "google/gemma-2-27b-it", - name: "Google: Gemma 2 27B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-06-24", - last_updated: "2024-06-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 0.65 }, - limit: { context: 8192, output: 2048 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Google: Gemma 3 27B", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-03-12", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.11, cache_read: 0.02 }, - limit: { context: 128000, output: 65536 }, - }, - "google/gemma-4-26b-a4b-it": { - id: "google/gemma-4-26b-a4b-it", - name: "Google: Gemma 4 26B A4B", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-03", - last_updated: "2026-04-11", - modalities: { input: ["image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.4 }, - limit: { context: 262144, output: 262144 }, - }, - "google/gemini-2.5-flash-lite": { - id: "google/gemini-2.5-flash-lite", - name: "Google: Gemini 2.5 Flash Lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-17", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, reasoning: 0.4, cache_read: 0.01, cache_write: 0.083333 }, - limit: { context: 1048576, output: 65535 }, - }, - "google/gemini-2.0-flash-lite-001": { - id: "google/gemini-2.0-flash-lite-001", - name: "Google: Gemini 2.0 Flash Lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-11", - last_updated: "2026-03-15", - modalities: { input: ["audio", "image", "pdf", "text", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 1048576, output: 8192 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "MoonshotAI: Kimi K2.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.2 }, - limit: { context: 262144, output: 65535 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "MoonshotAI: Kimi K2 0905", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2, cache_read: 0.15 }, - limit: { context: 131072, output: 26215 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "MoonshotAI: Kimi K2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - structured_output: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2": { - id: "moonshotai/kimi-k2", - name: "MoonshotAI: Kimi K2 0711", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-07-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 131000, output: 26215 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "MoonshotAI: Kimi K2 Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-11-06", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.47, output: 2, cache_read: 0.2 }, - limit: { context: 131072, output: 65535 }, - }, - "aion-labs/aion-1.0": { - id: "aion-labs/aion-1.0", - name: "AionLabs: Aion-1.0", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-02-05", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 4, output: 8 }, - limit: { context: 131072, output: 32768 }, - }, - "aion-labs/aion-rp-llama-3.1-8b": { - id: "aion-labs/aion-rp-llama-3.1-8b", - name: "AionLabs: Aion-RP 1.0 (8B)", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-02-05", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 1.6 }, - limit: { context: 32768, output: 32768 }, - }, - "aion-labs/aion-2.0": { - id: "aion-labs/aion-2.0", - name: "AionLabs: Aion-2.0", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 1.6 }, - limit: { context: 131072, output: 32768 }, - }, - "aion-labs/aion-1.0-mini": { - id: "aion-labs/aion-1.0-mini", - name: "AionLabs: Aion-1.0-Mini", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-02-05", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 1.4 }, - limit: { context: 131072, output: 32768 }, - }, - "~moonshotai/kimi-latest": { - id: "~moonshotai/kimi-latest", - name: "MoonshotAI: Kimi Latest", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-27", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.74, output: 3.49, cache_read: 0.14 }, - limit: { context: 262142, output: 262142 }, - }, - "thedrummer/unslopnemo-12b": { - id: "thedrummer/unslopnemo-12b", - name: "TheDrummer: UnslopNemo 12B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-11-09", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 32768, output: 32768 }, - }, - "thedrummer/cydonia-24b-v4.1": { - id: "thedrummer/cydonia-24b-v4.1", - name: "TheDrummer: Cydonia 24B V4.1", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-27", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.5 }, - limit: { context: 131072, output: 131072 }, - }, - "thedrummer/skyfall-36b-v2": { - id: "thedrummer/skyfall-36b-v2", - name: "TheDrummer: Skyfall 36B V2", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-11", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 0.8 }, - limit: { context: 32768, output: 32768 }, - }, - "thedrummer/rocinante-12b": { - id: "thedrummer/rocinante-12b", - name: "TheDrummer: Rocinante 12B", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-09-30", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.43 }, - limit: { context: 32768, output: 32768 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Anthropic: Claude Opus 4.1", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3.7-sonnet:thinking": { - id: "anthropic/claude-3.7-sonnet:thinking", - name: "Anthropic: Claude 3.7 Sonnet (thinking)", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-02-19", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4.6-fast": { - id: "anthropic/claude-opus-4.6-fast", - name: "Anthropic: Claude Opus 4.6 (Fast)", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-04-07", - last_updated: "2026-04-11", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 150, cache_read: 3, cache_write: 37.5 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-3.7-sonnet": { - id: "anthropic/claude-3.7-sonnet", - name: "Anthropic: Claude 3.7 Sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-02-19", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Anthropic: Claude Opus 4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.7": { - id: "anthropic/claude-opus-4.7", - name: "Anthropic: Claude Opus 4.7", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-16", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Anthropic: Claude Sonnet 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-22", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4.5": { - id: "anthropic/claude-sonnet-4.5", - name: "Anthropic: Claude Sonnet 4.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "anthropic/claude-opus-4.5": { - id: "anthropic/claude-opus-4.5", - name: "Anthropic: Claude Opus 4.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-11-24", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-3-haiku": { - id: "anthropic/claude-3-haiku", - name: "Anthropic: Claude 3 Haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-03-07", - last_updated: "2024-03-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Anthropic: Claude Opus 4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-22", - last_updated: "2026-03-15", - modalities: { input: ["image", "pdf", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3.5-haiku": { - id: "anthropic/claude-3.5-haiku", - name: "Anthropic: Claude 3.5 Haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Anthropic: Claude Haiku 4.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Anthropic: Claude Sonnet 4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 1000000, output: 128000 }, - }, - "switchpoint/router": { - id: "switchpoint/router", - name: "Switchpoint Router", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-07-12", - last_updated: "2026-03-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.85, output: 3.4 }, - limit: { context: 131072, output: 32768 }, - }, - "bytedance/ui-tars-1.5-7b": { - id: "bytedance/ui-tars-1.5-7b", - name: "ByteDance: UI-TARS 7B ", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-07-23", - last_updated: "2026-03-15", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.2 }, - limit: { context: 128000, output: 2048 }, - }, - "tngtech/deepseek-r1t2-chimera": { - id: "tngtech/deepseek-r1t2-chimera", - name: "TNG: DeepSeek R1T2 Chimera", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.85, cache_read: 0.125 }, - limit: { context: 163840, output: 163840 }, - }, - "xiaomi/mimo-v2.5-pro": { - id: "xiaomi/mimo-v2.5-pro", - name: "Xiaomi: MiMo V2.5 Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-omni": { - id: "xiaomi/mimo-v2-omni", - name: "Xiaomi: MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 262144, output: 65536 }, - }, - "xiaomi/mimo-v2.5": { - id: "xiaomi/mimo-v2.5", - name: "Xiaomi: MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-pro": { - id: "xiaomi/mimo-v2-pro", - name: "Xiaomi: MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "Xiaomi: MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.29, cache_read: 0.045 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - "sap-ai-core": { - id: "sap-ai-core", - env: ["AICORE_SERVICE_KEY"], - npm: "@jerome-benoit/sap-ai-provider-v2", - name: "SAP AI Core", - doc: "https://help.sap.com/docs/sap-ai-core", - models: { - "anthropic--claude-4.6-opus": { - id: "anthropic--claude-4.6-opus", - name: "anthropic--claude-4.6-opus", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic--claude-3-haiku": { - id: "anthropic--claude-3-haiku", - name: "anthropic--claude-3-haiku", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-13", - last_updated: "2024-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic--claude-3-opus": { - id: "anthropic--claude-3-opus", - name: "anthropic--claude-3-opus", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-02-29", - last_updated: "2024-02-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 4096 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "gpt-5-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "gpt-5-nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "gemini-2.5-pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-25", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic--claude-3.7-sonnet": { - id: "anthropic--claude-3.7-sonnet", - name: "anthropic--claude-3.7-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "sonar-pro": { - id: "sonar-pro", - name: "sonar-pro", - family: "sonar-pro", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic--claude-4.5-sonnet": { - id: "anthropic--claude-4.5-sonnet", - name: "anthropic--claude-4.5-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic--claude-4.6-sonnet": { - id: "anthropic--claude-4.6-sonnet", - name: "anthropic--claude-4.6-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "sonar-deep-research": { - id: "sonar-deep-research", - name: "sonar-deep-research", - family: "sonar-deep-research", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-02-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, reasoning: 3 }, - limit: { context: 128000, output: 32768 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "gemini-2.5-flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-25", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic--claude-4.5-opus": { - id: "anthropic--claude-4.5-opus", - name: "anthropic--claude-4.5-opus", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - sonar: { - id: "sonar", - name: "sonar", - family: "sonar", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 128000, output: 4096 }, - }, - "anthropic--claude-4-opus": { - id: "anthropic--claude-4-opus", - name: "anthropic--claude-4-opus", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic--claude-3-sonnet": { - id: "anthropic--claude-3-sonnet", - name: "anthropic--claude-3-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-04", - last_updated: "2024-03-04", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic--claude-4-sonnet": { - id: "anthropic--claude-4-sonnet", - name: "anthropic--claude-4-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "gemini-2.5-flash-lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic--claude-4.5-haiku": { - id: "anthropic--claude-4.5-haiku", - name: "anthropic--claude-4.5-haiku", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "gpt-5": { - id: "gpt-5", - name: "gpt-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "gpt-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "gpt-4.1-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "anthropic--claude-3.5-sonnet": { - id: "anthropic--claude-3.5-sonnet", - name: "anthropic--claude-3.5-sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - }, - }, - morph: { - id: "morph", - env: ["MORPH_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.morphllm.com/v1", - name: "Morph", - doc: "https://docs.morphllm.com/api-reference/introduction", - models: { - auto: { - id: "auto", - name: "Auto", - family: "auto", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.85, output: 1.55 }, - limit: { context: 32000, output: 32000 }, - }, - "morph-v3-fast": { - id: "morph-v3-fast", - name: "Morph v3 Fast", - family: "morph", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 1.2 }, - limit: { context: 16000, output: 16000 }, - }, - "morph-v3-large": { - id: "morph-v3-large", - name: "Morph v3 Large", - family: "morph", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9, output: 1.9 }, - limit: { context: 32000, output: 32000 }, - }, - }, - }, - "cloudflare-ai-gateway": { - id: "cloudflare-ai-gateway", - env: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_GATEWAY_ID"], - npm: "ai-gateway-provider", - name: "Cloudflare AI Gateway", - doc: "https://developers.cloudflare.com/ai-gateway/", - models: { - "workers-ai/@cf/myshell-ai/melotts": { - id: "workers-ai/@cf/myshell-ai/melotts", - name: "MyShell MeloTTS", - family: "melotts", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - 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", - name: "IBM Granite 4.0 H Micro", - family: "granite", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.017, output: 0.11 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/huggingface/distilbert-sst-2-int8": { - id: "workers-ai/@cf/huggingface/distilbert-sst-2-int8", - name: "DistilBERT SST-2 INT8", - family: "distilbert", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.026, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/zai-org/glm-4.7-flash": { - id: "workers-ai/@cf/zai-org/glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4 }, - limit: { context: 131072, output: 131072 }, - }, - "workers-ai/@cf/pipecat-ai/smart-turn-v2": { - id: "workers-ai/@cf/pipecat-ai/smart-turn-v2", - name: "Pipecat Smart Turn v2", - family: "smart-turn", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - 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", - name: "Mistral Small 3.1 24B Instruct", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 0.56 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/facebook/bart-large-cnn": { - id: "workers-ai/@cf/facebook/bart-large-cnn", - name: "BART Large CNN", - family: "bart", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-09", - last_updated: "2025-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - 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", - name: "Gemma SEA-LION v4 27B IT", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 0.56 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/nvidia/nemotron-3-120b-a12b": { - id: "workers-ai/@cf/nvidia/nemotron-3-120b-a12b", - name: "Nemotron 3 Super 120B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - 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", - name: "DeepSeek R1 Distill Qwen 32B", - family: "deepseek-thinking", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 4.88 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/openai/gpt-oss-20b": { - id: "workers-ai/@cf/openai/gpt-oss-20b", - name: "GPT OSS 20B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/openai/gpt-oss-120b": { - id: "workers-ai/@cf/openai/gpt-oss-120b", - name: "GPT OSS 120B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 0.75 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1": { - id: "workers-ai/@cf/mistral/mistral-7b-instruct-v0.1", - name: "Mistral 7B Instruct v0.1", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.11, output: 0.19 }, - 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", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.85 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-3-8b-instruct-awq": { - id: "workers-ai/@cf/meta/llama-3-8b-instruct-awq", - name: "Llama 3 8B Instruct AWQ", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0.27 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-guard-3-8b": { - id: "workers-ai/@cf/meta/llama-guard-3-8b", - name: "Llama Guard 3 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.48, output: 0.03 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/m2m100-1.2b": { - id: "workers-ai/@cf/meta/m2m100-1.2b", - name: "M2M100 1.2B", - family: "m2m", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.34, output: 0.34 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-2-7b-chat-fp16": { - id: "workers-ai/@cf/meta/llama-2-7b-chat-fp16", - name: "Llama 2 7B Chat FP16", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 6.67 }, - 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", - name: "Llama 3.2 11B Vision Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049, output: 0.68 }, - 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", - name: "Llama 3.3 70B Instruct FP8 Fast", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 2.25 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-3.2-1b-instruct": { - id: "workers-ai/@cf/meta/llama-3.2-1b-instruct", - name: "Llama 3.2 1B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.027, output: 0.2 }, - 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", - name: "Llama 3.1 8B Instruct FP8", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.29 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-3.2-3b-instruct": { - id: "workers-ai/@cf/meta/llama-3.2-3b-instruct", - name: "Llama 3.2 3B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.051, output: 0.34 }, - 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", - name: "Llama 3.1 8B Instruct AWQ", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0.27 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-3-8b-instruct": { - id: "workers-ai/@cf/meta/llama-3-8b-instruct", - name: "Llama 3 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 0.83 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/meta/llama-3.1-8b-instruct": { - id: "workers-ai/@cf/meta/llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 0.8299999999999998 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct": { - id: "workers-ai/@cf/qwen/qwen2.5-coder-32b-instruct", - name: "Qwen 2.5 Coder 32B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.66, output: 1 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/qwen/qwen3-embedding-0.6b": { - id: "workers-ai/@cf/qwen/qwen3-embedding-0.6b", - name: "Qwen3 Embedding 0.6B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.012, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/qwen/qwq-32b": { - id: "workers-ai/@cf/qwen/qwq-32b", - name: "QwQ 32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.66, output: 1 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8": { - id: "workers-ai/@cf/qwen/qwen3-30b-a3b-fp8", - name: "Qwen3 30B A3B FP8", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.051, output: 0.34 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/google/gemma-3-12b-it": { - id: "workers-ai/@cf/google/gemma-3-12b-it", - name: "Gemma 3 12B IT", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 0.56 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/moonshotai/kimi-k2.5": { - id: "workers-ai/@cf/moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 256000, output: 256000 }, - }, - "workers-ai/@cf/moonshotai/kimi-k2.6": { - id: "workers-ai/@cf/moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 256000, output: 256000 }, - }, - "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1B": { - id: "workers-ai/@cf/ai4bharat/indictrans2-en-indic-1B", - name: "IndicTrans2 EN-Indic 1B", - family: "indictrans", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.34, output: 0.34 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/pfnet/plamo-embedding-1b": { - id: "workers-ai/@cf/pfnet/plamo-embedding-1b", - name: "PLaMo Embedding 1B", - family: "plamo", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.019, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/baai/bge-small-en-v1.5": { - id: "workers-ai/@cf/baai/bge-small-en-v1.5", - name: "BGE Small EN v1.5", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/baai/bge-large-en-v1.5": { - id: "workers-ai/@cf/baai/bge-large-en-v1.5", - name: "BGE Large EN v1.5", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/baai/bge-reranker-base": { - id: "workers-ai/@cf/baai/bge-reranker-base", - name: "BGE Reranker Base", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-09", - last_updated: "2025-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0031, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/baai/bge-base-en-v1.5": { - id: "workers-ai/@cf/baai/bge-base-en-v1.5", - name: "BGE Base EN v1.5", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.067, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/baai/bge-m3": { - id: "workers-ai/@cf/baai/bge-m3", - name: "BGE M3", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.012, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/deepgram/aura-2-en": { - id: "workers-ai/@cf/deepgram/aura-2-en", - name: "Deepgram Aura 2 (EN)", - family: "aura", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/deepgram/aura-2-es": { - id: "workers-ai/@cf/deepgram/aura-2-es", - name: "Deepgram Aura 2 (ES)", - family: "aura", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "workers-ai/@cf/deepgram/nova-3": { - id: "workers-ai/@cf/deepgram/nova-3", - name: "Deepgram Nova 3", - family: "nova", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "ai-gateway-provider" }, - }, - "openai/gpt-4-turbo": { - id: "openai/gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/o3-pro": { - id: "openai/o3-pro", - name: "o3-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-06-10", - last_updated: "2025-06-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 80 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "ai-gateway-provider" }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/o1": { - id: "openai/o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-3.5-turbo": { - id: "openai/gpt-3.5-turbo", - name: "GPT-3.5-turbo", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2021-09-01", - release_date: "2023-03-01", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5, cache_read: 1.25 }, - limit: { context: 16385, output: 4096 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4": { - id: "openai/gpt-4", - name: "GPT-4", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-11", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 60 }, - limit: { context: 8192, output: 8192 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "ai-gateway-provider" }, - }, - "openai/o3": { - id: "openai/o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "anthropic/claude-haiku-4-5": { - id: "anthropic/claude-haiku-4-5", - name: "Claude Haiku 4.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4-6": { - id: "anthropic/claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "ai-gateway-provider" }, - }, - "anthropic/claude-opus-4-7": { - id: "anthropic/claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "anthropic/claude-opus-4-1": { - id: "anthropic/claude-opus-4-1", - name: "Claude Opus 4.1 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3-5-haiku": { - id: "anthropic/claude-3-5-haiku", - name: "Claude Haiku 3.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-3.5-sonnet": { - id: "anthropic/claude-3.5-sonnet", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4 (latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4-5": { - id: "anthropic/claude-opus-4-5", - name: "Claude Opus 4.5 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-3-haiku": { - id: "anthropic/claude-3-haiku", - name: "Claude Haiku 3", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-13", - last_updated: "2024-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude Opus 4 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-opus-4-6": { - id: "anthropic/claude-opus-4-6", - name: "Claude Opus 4.6 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-3.5-haiku": { - id: "anthropic/claude-3.5-haiku", - name: "Claude Haiku 3.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-sonnet-4-5": { - id: "anthropic/claude-sonnet-4-5", - name: "Claude Sonnet 4.5 (latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-3-sonnet": { - id: "anthropic/claude-3-sonnet", - name: "Claude Sonnet 3", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-04", - last_updated: "2024-03-04", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic/claude-3-opus": { - id: "anthropic/claude-3-opus", - name: "Claude Opus 3", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-02-29", - last_updated: "2024-02-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 4096 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - }, - }, - "github-copilot": { - id: "github-copilot", - env: ["GITHUB_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.githubcopilot.com", - name: "GitHub Copilot", - doc: "https://docs.github.com/en/copilot", - models: { - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1-Codex-max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-12-04", - last_updated: "2025-12-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 128000, output: 128000 }, - status: "deprecated", - }, - "claude-opus-4.6": { - id: "claude-opus-4.6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 144000, input: 128000, output: 64000 }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 128000, output: 64000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 128000, output: 64000 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-08-13", - last_updated: "2025-08-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 264000, input: 128000, output: 64000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 128000, output: 64000 }, - status: "deprecated", - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 128000, output: 64000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 264000, input: 128000, output: 64000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-opus-4.7": { - id: "claude-opus-4.7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 144000, input: 128000, output: 64000 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1-Codex-mini", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 128000, output: 128000 }, - status: "deprecated", - }, - "claude-sonnet-4": { - id: "claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 216000, input: 128000, output: 16000 }, - status: "deprecated", - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-27", - last_updated: "2025-08-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 128000, output: 64000 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 264000, input: 128000, output: 64000 }, - status: "deprecated", - }, - "claude-sonnet-4.5": { - id: "claude-sonnet-4.5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 144000, input: 128000, output: 32000 }, - }, - "claude-opus-41": { - id: "claude-opus-41", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 80000, output: 16000 }, - status: "deprecated", - }, - "claude-opus-4.5": { - id: "claude-opus-4.5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 160000, input: 128000, output: 32000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 64000, output: 4096 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - status: "deprecated", - }, - "claude-haiku-4.5": { - id: "claude-haiku-4.5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 144000, input: 128000, output: 32000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, input: 64000, output: 16384 }, - }, - "claude-sonnet-4.6": { - id: "claude-sonnet-4.6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, input: 128000, output: 32000 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 128000, output: 128000 }, - status: "deprecated", - }, - }, - }, - mixlayer: { - id: "mixlayer", - env: ["MIXLAYER_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://models.mixlayer.ai/v1", - name: "Mixlayer", - doc: "https://docs.mixlayer.com", - models: { - "qwen/qwen3.5-122b-a10b": { - id: "qwen/qwen3.5-122b-a10b", - name: "Qwen3.5 122B A10B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 3.2 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3.5-27b": { - id: "qwen/qwen3.5-27b", - name: "Qwen3.5 27B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 2.4 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3.5-9b": { - id: "qwen/qwen3.5-9b", - name: "Qwen3.5 9B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen/qwen3.5-35b-a3b": { - id: "qwen/qwen3.5-35b-a3b", - name: "Qwen3.5 35B A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1.3 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - "xiaomi-token-plan-sgp": { - id: "xiaomi-token-plan-sgp", - env: ["XIAOMI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://token-plan-sgp.xiaomimimo.com/v1", - name: "Xiaomi Token Plan (Singapore)", - doc: "https://platform.xiaomimimo.com/#/docs", - models: { - "mimo-v2-tts": { - id: "mimo-v2-tts", - name: "MiMo-V2-TTS", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 16384 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - }, - }, - zai: { - id: "zai", - env: ["ZHIPU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.z.ai/api/paas/v4", - name: "Z.AI", - doc: "https://docs.z.ai/guides/overview/pricing", - models: { - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4, cache_read: 0.24, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.7-flashx": { - id: "glm-4.7-flashx", - name: "GLM-4.7-FlashX", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4, cache_read: 0.01, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 4.4, cache_read: 0.26, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1, cache_read: 0.03, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-5-turbo": { - id: "glm-5-turbo", - name: "GLM-5-Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4, cache_read: 0.24, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.5v": { - id: "glm-4.5v", - name: "GLM-4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 64000, output: 16384 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.6v": { - id: "glm-4.6v", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 128000, output: 32768 }, - }, - "glm-4.5-flash": { - id: "glm-4.5-flash", - name: "GLM-4.5-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.7-flash": { - id: "glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - }, - }, - opencode: { - id: "opencode", - env: ["OPENCODE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://opencode.ai/zen/v1", - name: "OpenCode Zen", - doc: "https://opencode.ai/docs/zen", - models: { - "minimax-m2.7": { - id: "minimax-m2.7", - name: "MiniMax M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.08 }, - limit: { context: 262144, output: 65536 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.1 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.7-free": { - id: "glm-4.7-free", - name: "GLM-4.7 Free", - family: "glm-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - }, - "gemini-3.1-pro": { - id: "gemini-3.1-pro", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - provider: { npm: "@ai-sdk/google" }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "kimi-k2.5-free": { - id: "kimi-k2.5-free", - name: "Kimi K2.5 Free", - family: "kimi-free", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 262144 }, - status: "deprecated", - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "minimax-m2.5-free": { - id: "minimax-m2.5-free", - name: "MiniMax M2.5 Free", - family: "minimax-free", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 131072 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "ring-2.6-1t-free": { - id: "ring-2.6-1t-free", - name: "Ring 2.6 1T Free", - family: "ring-1t-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-06", - release_date: "2026-05-08", - last_updated: "2026-05-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262000, output: 66000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "big-pickle": { - id: "big-pickle", - name: "Big Pickle", - family: "big-pickle", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-10-17", - last_updated: "2025-10-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 128000 }, - }, - "claude-opus-4-1": { - id: "claude-opus-4-1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen3.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05, cache_write: 0.625 }, - limit: { context: 262144, output: 65536 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "claude-3-5-haiku": { - id: "claude-3-5-haiku", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - status: "deprecated", - provider: { npm: "@ai-sdk/anthropic" }, - }, - "minimax-m2.1": { - id: "minimax-m2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.1 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 204800, output: 131072 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex Mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "claude-sonnet-4": { - id: "claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "gemini-3-flash": { - id: "gemini-3-flash", - name: "Gemini 3 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05 }, - limit: { context: 1048576, output: 65536 }, - provider: { npm: "@ai-sdk/google" }, - }, - "trinity-large-preview-free": { - id: "trinity-large-preview-free", - name: "Trinity Large Preview", - family: "trinity", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-01-28", - last_updated: "2026-01-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - status: "deprecated", - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.07, output: 8.5, cache_read: 0.107 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, cache_read: 30 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "glm-5-free": { - id: "glm-5-free", - name: "GLM-5 Free", - family: "glm-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "minimax-m2.1-free": { - id: "minimax-m2.1-free", - name: "MiniMax M2.1 Free", - family: "minimax-free", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - provider: { npm: "@ai-sdk/anthropic" }, - }, - "qwen3.6-plus-free": { - id: "qwen3.6-plus-free", - name: "Qwen3.6 Plus Free", - family: "qwen-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 1048576, output: 64000 }, - status: "deprecated", - }, - "glm-4.6": { - id: "glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.1 }, - limit: { context: 204800, output: 131072 }, - status: "deprecated", - }, - "ling-2.6-flash-free": { - id: "ling-2.6-flash-free", - name: "Ling 2.6 Flash Free", - family: "ling-flash-free", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262100, output: 32800 }, - status: "deprecated", - }, - "gemini-3-pro": { - id: "gemini-3-pro", - name: "Gemini 3 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - status: "deprecated", - provider: { npm: "@ai-sdk/google" }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 65536 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "GPT-5 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.07, output: 8.5, cache_read: 0.107 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "grok-code": { - id: "grok-code", - name: "Grok Code Fast 1", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-20", - last_updated: "2025-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 256000, output: 256000 }, - status: "deprecated", - }, - "mimo-v2-flash-free": { - id: "mimo-v2-flash-free", - name: "MiMo V2 Flash Free", - family: "mimo-flash-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 65536 }, - status: "deprecated", - }, - "gpt-5.3-codex-spark": { - id: "gpt-5.3-codex-spark", - name: "GPT-5.3 Codex Spark", - family: "gpt-codex-spark", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, input: 128000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "hy3-preview-free": { - id: "hy3-preview-free", - name: "Hy3 preview Free", - family: "hy3-free", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 256000, output: 64000 }, - status: "deprecated", - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "kimi-k2": { - id: "kimi-k2", - name: "Kimi K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2.5, cache_read: 0.4 }, - limit: { context: 262144, output: 262144 }, - status: "deprecated", - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 64000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "qwen3-coder": { - id: "qwen3-coder", - name: "Qwen3 Coder", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 1.8 }, - limit: { context: 262144, output: 65536 }, - status: "deprecated", - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.07, output: 8.5, cache_read: 0.107 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen3.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.2, cache_read: 0.02, cache_write: 0.25 }, - limit: { context: 262144, output: 65536 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - "mimo-v2-pro-free": { - id: "mimo-v2-pro-free", - name: "MiMo V2 Pro Free", - family: "mimo-pro-free", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 1048576, output: 64000 }, - status: "deprecated", - }, - "nemotron-3-super-free": { - id: "nemotron-3-super-free", - name: "Nemotron 3 Super Free", - family: "nemotron-free", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2026-02", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 128000 }, - }, - "gpt-5.5-pro": { - id: "gpt-5.5-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, cache_read: 30 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2.5, cache_read: 0.4 }, - limit: { context: 262144, output: 262144 }, - status: "deprecated", - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.07, output: 8.5, cache_read: 0.107 }, - limit: { context: 400000, input: 272000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "mimo-v2-omni-free": { - id: "mimo-v2-omni-free", - name: "MiMo V2 Omni Free", - family: "mimo-omni-free", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 64000 }, - status: "deprecated", - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - provider: { npm: "@ai-sdk/openai" }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/anthropic" }, - }, - }, - }, - stepfun: { - id: "stepfun", - env: ["STEPFUN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.stepfun.com/v1", - name: "StepFun", - doc: "https://platform.stepfun.com/docs/zh/overview/concept", - models: { - "step-3.5-flash-2603": { - id: "step-3.5-flash-2603", - name: "Step 3.5 Flash 2603", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.02 }, - limit: { context: 256000, input: 256000, output: 256000 }, - }, - "step-1-32k": { - id: "step-1-32k", - name: "Step 1 (32K)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-01", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.05, output: 9.59, cache_read: 0.41 }, - limit: { context: 32768, input: 32768, output: 32768 }, - }, - "step-3.5-flash": { - id: "step-3.5-flash", - name: "Step 3.5 Flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-29", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.096, output: 0.288, cache_read: 0.019 }, - limit: { context: 256000, input: 256000, output: 256000 }, - }, - "step-2-16k": { - id: "step-2-16k", - name: "Step 2 (16K)", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-01", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5.21, output: 16.44, cache_read: 1.04 }, - limit: { context: 16384, input: 16384, output: 8192 }, - }, - }, - }, - nebius: { - id: "nebius", - env: ["NEBIUS_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.tokenfactory.nebius.com/v1", - name: "Nebius Token Factory", - doc: "https://docs.tokenfactory.nebius.com/", - models: { - "NousResearch/Hermes-4-70B": { - id: "NousResearch/Hermes-4-70B", - name: "Hermes-4-70B", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-11", - release_date: "2026-01-30", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4, reasoning: 0.4, cache_read: 0.013, cache_write: 0.16 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "NousResearch/Hermes-4-405B": { - id: "NousResearch/Hermes-4-405B", - name: "Hermes-4-405B", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-11", - release_date: "2026-01-30", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, reasoning: 3, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "Qwen/Qwen2.5-VL-72B-Instruct": { - id: "Qwen/Qwen2.5-VL-72B-Instruct", - name: "Qwen2.5-VL-72B-Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-20", - last_updated: "2026-02-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.75, cache_read: 0.025, cache_write: 0.31 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "Qwen/Qwen3.5-397B-A17B": { - id: "Qwen/Qwen3.5-397B-A17B", - name: "Qwen3.5-397B-A17B", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-15", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6, cache_read: 0.06, cache_write: 0.75 }, - limit: { context: 262144, input: 250000, output: 8192 }, - }, - "Qwen/Qwen3-Embedding-8B": { - id: "Qwen/Qwen3-Embedding-8B", - name: "Qwen3-Embedding-8B", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: false, - knowledge: "2025-10", - release_date: "2026-01-10", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0 }, - limit: { context: 32768, input: 32768, output: 0 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen3-30B-A3B-Instruct-2507", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-01-28", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01, cache_write: 0.125 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-25", - last_updated: "2025-10-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 262144, output: 8192 }, - }, - "Qwen/Qwen3-32B": { - id: "Qwen/Qwen3-32B", - name: "Qwen3-32B", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-01-28", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01, cache_write: 0.125 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507-fast": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507-fast", - name: "Qwen3-235B-A22B-Thinking-2507-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-25", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2, cache_read: 0.05, cache_write: 0.625 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "Qwen/Qwen3.5-397B-A17B-fast": { - id: "Qwen/Qwen3.5-397B-A17B-fast", - name: "Qwen3.5-397B-A17B-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-15", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6, cache_read: 0.06, cache_write: 0.75 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Thinking-fast": { - id: "Qwen/Qwen3-Next-80B-A3B-Thinking-fast", - name: "Qwen3-Next-80B-A3B-Thinking-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-25", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.2, cache_read: 0.015, cache_write: 0.1875 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Thinking": { - id: "Qwen/Qwen3-Next-80B-A3B-Thinking", - name: "Qwen3-Next-80B-A3B-Thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-01-28", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.2, reasoning: 1.2, cache_read: 0.015, cache_write: 0.18 }, - limit: { context: 128000, input: 120000, output: 16384 }, - }, - "PrimeIntellect/INTELLECT-3": { - id: "PrimeIntellect/INTELLECT-3", - name: "INTELLECT-3", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-10", - release_date: "2026-01-25", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1, cache_read: 0.02, cache_write: 0.25 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-03-01", - last_updated: "2026-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3.2, cache_read: 0.1, cache_write: 1 }, - limit: { context: 200000, input: 200000, output: 16384 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama-3.3-70B-Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-12-05", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.4, cache_read: 0.013, cache_write: 0.16 }, - limit: { context: 128000, input: 120000, output: 8192 }, - }, - "meta-llama/Meta-Llama-3.1-8B-Instruct": { - id: "meta-llama/Meta-Llama-3.1-8B-Instruct", - name: "Meta-Llama-3.1-8B-Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-07-23", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.06, cache_read: 0.002, cache_write: 0.025 }, - limit: { context: 128000, input: 120000, output: 4096 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "Nemotron-3-Super-120B-A12B", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-02", - release_date: "2026-03-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, input: 256000, output: 32768 }, - }, - "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1": { - id: "nvidia/Llama-3_1-Nemotron-Ultra-253B-v1", - name: "Llama-3.1-Nemotron-Ultra-253B-v1", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-15", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8, cache_read: 0.06, cache_write: 0.75 }, - limit: { context: 128000, input: 120000, output: 4096 }, - }, - "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B": { - id: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B", - name: "Nemotron-3-Nano-30B-A3B", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-08-10", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.24, cache_read: 0.006, cache_write: 0.075 }, - limit: { context: 32000, input: 30000, output: 4096 }, - }, - "nvidia/Nemotron-3-Nano-Omni": { - id: "nvidia/Nemotron-3-Nano-Omni", - name: "Nemotron-3-Nano-Omni", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.24, cache_read: 0.006, cache_write: 0.075 }, - limit: { context: 65536, input: 60000, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V3.2-fast": { - id: "deepseek-ai/DeepSeek-V3.2-fast", - name: "DeepSeek-V3.2-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2, cache_read: 0.04, cache_write: 0.5 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek-V3.2", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-11", - release_date: "2026-01-20", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.45, reasoning: 0.45, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 163000, input: 160000, output: 16384 }, - }, - "openai/gpt-oss-120b-fast": { - id: "openai/gpt-oss-120b-fast", - name: "gpt-oss-120b-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-06-10", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5, cache_read: 0.01, cache_write: 0.125 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "gpt-oss-120b", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-09", - release_date: "2026-01-10", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6, reasoning: 0.6, cache_read: 0.015, cache_write: 0.18 }, - limit: { context: 128000, input: 124000, output: 8192 }, - }, - "google/gemma-2-2b-it": { - id: "google/gemma-2-2b-it", - name: "Gemma-2-2b-it", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2024-06", - release_date: "2024-07-31", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.06, cache_read: 0.002, cache_write: 0.025 }, - limit: { context: 8192, input: 8000, output: 4096 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Gemma-3-27b-it", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-10", - release_date: "2026-01-20", - last_updated: "2026-02-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01, cache_write: 0.125 }, - limit: { context: 110000, input: 100000, output: 8192 }, - }, - "moonshotai/Kimi-K2.5-fast": { - id: "moonshotai/Kimi-K2.5-fast", - name: "Kimi-K2.5-fast", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-15", - last_updated: "2026-02-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.5, cache_read: 0.05, cache_write: 0.625 }, - limit: { context: 256000, input: 256000, output: 8192 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi-K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-12-15", - last_updated: "2026-02-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.5, reasoning: 2.5, cache_read: 0.05, cache_write: 0.625 }, - limit: { context: 256000, input: 256000, output: 8192 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 196608, input: 190000, output: 8192 }, - }, - "MiniMaxAI/MiniMax-M2.5-fast": { - id: "MiniMaxAI/MiniMax-M2.5-fast", - name: "MiniMax-M2.5-fast", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2026-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 8000, input: 7000, output: 8192 }, - }, - "deepseek-ai/DeepSeek-V4-Pro": { - id: "deepseek-ai/DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.75, output: 3.5, cache_read: 0.15 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - poe: { - id: "poe", - env: ["POE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.poe.com/v1", - name: "Poe", - doc: "https://creator.poe.com/docs/external-applications/openai-compatible-api", - models: { - "topazlabs-co/topazlabs": { - id: "topazlabs-co/topazlabs", - name: "TopazLabs", - family: "topazlabs", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 204, output: 0 }, - }, - "novita/kimi-k2.5": { - id: "novita/kimi-k2.5", - name: "Kimi-K2.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 128000, output: 262144 }, - }, - "novita/glm-4.7": { - id: "novita/glm-4.7", - name: "glm-4.7", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 205000, output: 131072 }, - status: "deprecated", - }, - "novita/glm-5": { - id: "novita/glm-5", - name: "GLM-5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 205000, output: 131072 }, - }, - "novita/minimax-m2.1": { - id: "novita/minimax-m2.1", - name: "minimax-m2.1", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-26", - last_updated: "2025-12-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 205000, output: 131072 }, - }, - "novita/glm-4.6": { - id: "novita/glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "novita/kimi-k2.6": { - id: "novita/kimi-k2.6", - name: "Kimi-K2.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-20", - last_updated: "2026-05-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.96, output: 4.04, cache_read: 0.16 }, - limit: { context: 262144, input: 262144, output: 262144 }, - }, - "novita/glm-4.6v": { - id: "novita/glm-4.6v", - name: "glm-4.6v", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 131000, output: 32768 }, - }, - "novita/deepseek-v3.2": { - id: "novita/deepseek-v3.2", - name: "DeepSeek-V3.2", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.4, cache_read: 0.13 }, - limit: { context: 128000, output: 0 }, - }, - "novita/glm-4.7-flash": { - id: "novita/glm-4.7-flash", - name: "glm-4.7-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 200000, output: 65500 }, - }, - "novita/glm-4.7-n": { - id: "novita/glm-4.7-n", - name: "glm-4.7-n", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 205000, output: 131072 }, - }, - "novita/kimi-k2-thinking": { - id: "novita/kimi-k2-thinking", - name: "kimi-k2-thinking", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-07", - last_updated: "2025-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 0 }, - }, - "fireworks-ai/kimi-k2.5-fw": { - id: "fireworks-ai/kimi-k2.5-fw", - name: "Kimi-K2.5-FW", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, input: 245760, output: 16384 }, - }, - "empiriolabs/deepseek-v4-pro-el": { - id: "empiriolabs/deepseek-v4-pro-el", - name: "DeepSeek-V4-Pro-EL", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-04-24", - last_updated: "2026-05-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.67, output: 3.33 }, - limit: { context: 1000000, input: 1000000, output: 384000 }, - }, - "empiriolabs/deepseek-v4-flash-el": { - id: "empiriolabs/deepseek-v4-flash-el", - name: "DeepSeek-V4-Flash-EL", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-04-24", - last_updated: "2026-05-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28 }, - limit: { context: 1000000, input: 1000000, output: 384000 }, - }, - "elevenlabs/elevenlabs-v2.5-turbo": { - id: "elevenlabs/elevenlabs-v2.5-turbo", - name: "ElevenLabs-v2.5-Turbo", - family: "elevenlabs", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-10-28", - last_updated: "2024-10-28", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 128000, output: 0 }, - }, - "elevenlabs/elevenlabs-v3": { - id: "elevenlabs/elevenlabs-v3", - name: "ElevenLabs-v3", - family: "elevenlabs", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 128000, output: 0 }, - }, - "elevenlabs/elevenlabs-music": { - id: "elevenlabs/elevenlabs-music", - name: "ElevenLabs-Music", - family: "elevenlabs", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-08-29", - last_updated: "2025-08-29", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 2000, output: 0 }, - }, - "cerebras/gpt-oss-120b-cs": { - id: "cerebras/gpt-oss-120b-cs", - name: "GPT-OSS-120B-CS", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 0.75 }, - limit: { context: 128000, output: 0 }, - }, - "cerebras/llama-3.1-8b-cs": { - id: "cerebras/llama-3.1-8b-cs", - name: "Llama-3.1-8B-CS", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-05-13", - last_updated: "2025-05-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 0 }, - }, - "cerebras/qwen3-32b-cs": { - id: "cerebras/qwen3-32b-cs", - name: "qwen3-32b-cs", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-05-15", - last_updated: "2025-05-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - status: "deprecated", - }, - "cerebras/qwen3-235b-2507-cs": { - id: "cerebras/qwen3-235b-2507-cs", - name: "qwen3-235b-2507-cs", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-06", - last_updated: "2025-08-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - status: "deprecated", - }, - "cerebras/llama-3.3-70b-cs": { - id: "cerebras/llama-3.3-70b-cs", - name: "llama-3.3-70b-cs", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-13", - last_updated: "2025-05-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - status: "deprecated", - }, - "stabilityai/stablediffusionxl": { - id: "stabilityai/stablediffusionxl", - name: "StableDiffusionXL", - family: "stable-diffusion", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-07-09", - last_updated: "2023-07-09", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 200, output: 0 }, - }, - "xai/grok-code-fast-1": { - id: "xai/grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-22", - last_updated: "2025-08-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 128000 }, - }, - "xai/grok-4-fast-reasoning": { - id: "xai/grok-4-fast-reasoning", - name: "Grok-4-Fast-Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-09-16", - last_updated: "2025-09-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 128000 }, - }, - "xai/grok-4.1-fast-non-reasoning": { - id: "xai/grok-4.1-fast-non-reasoning", - name: "Grok-4.1-Fast-Non-Reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 30000 }, - }, - "xai/grok-4": { - id: "xai/grok-4", - name: "Grok-4", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 128000 }, - }, - "xai/grok-3-mini": { - id: "xai/grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - "xai/grok-4.20-multi-agent": { - id: "xai/grok-4.20-multi-agent", - name: "Grok-4.20-Multi-Agent", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2026-03-13", - last_updated: "2026-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2 }, - limit: { context: 128000, output: 0 }, - }, - "xai/grok-3": { - id: "xai/grok-3", - name: "Grok 3", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-04-11", - last_updated: "2025-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "xai/grok-4-fast-non-reasoning": { - id: "xai/grok-4-fast-non-reasoning", - name: "Grok-4-Fast-Non-Reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-09-16", - last_updated: "2025-09-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 128000 }, - }, - "xai/grok-4.1-fast-reasoning": { - id: "xai/grok-4.1-fast-reasoning", - name: "Grok-4.1-Fast-Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 2000000, output: 30000 }, - }, - "runwayml/runway": { - id: "runwayml/runway", - name: "Runway", - family: "runway", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-10-11", - last_updated: "2024-10-11", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 256, output: 0 }, - }, - "runwayml/runway-gen-4-turbo": { - id: "runwayml/runway-gen-4-turbo", - name: "Runway-Gen-4-Turbo", - family: "runway", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-05-09", - last_updated: "2025-05-09", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 256, output: 0 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "GPT-5.1-Codex-Max", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/sora-2-pro": { - id: "openai/sora-2-pro", - name: "Sora-2-Pro", - family: "sora", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "openai/chatgpt-4o-latest": { - id: "openai/chatgpt-4o-latest", - name: "ChatGPT-4o-Latest", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-08-14", - last_updated: "2024-08-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 4.5, output: 14 }, - limit: { context: 128000, output: 8192 }, - status: "deprecated", - }, - "openai/gpt-5-chat": { - id: "openai/gpt-5-chat", - name: "GPT-5-Chat", - family: "gpt-codex", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT-5.2-Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 19, output: 150 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4o-aug": { - id: "openai/gpt-4o-aug", - name: "GPT-4o-Aug", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-11-21", - last_updated: "2024-11-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.2, output: 9, cache_read: 1.1 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-image-2": { - id: "openai/gpt-image-2", - name: "GPT-Image-2", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - cost: { input: 5.0505, output: 32.3232, cache_read: 1.2626 }, - limit: { context: 0, output: 0 }, - }, - "openai/gpt-4-classic-0314": { - id: "openai/gpt-4-classic-0314", - name: "GPT-4-Classic-0314", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-08-26", - last_updated: "2024-08-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 27, output: 54 }, - limit: { context: 8192, output: 4096 }, - status: "deprecated", - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5-mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-06-25", - last_updated: "2025-06-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.22, output: 1.8, cache_read: 0.022 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT-5-nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.045, output: 0.36, cache_read: 0.0045 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT-5.3-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-10", - last_updated: "2026-02-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 13, cache_read: 0.16 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4-turbo": { - id: "openai/gpt-4-turbo", - name: "GPT-4-Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-09-13", - last_updated: "2023-09-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 9, output: 27 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 13, cache_read: 0.16 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/o3-pro": { - id: "openai/o3-pro", - name: "o3-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-06-10", - last_updated: "2025-06-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 18, output: 72 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3-mini-high": { - id: "openai/o3-mini-high", - name: "o3-mini-high", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.99, output: 4 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.54, cache_read: 0.068 }, - limit: { context: 124096, output: 4096 }, - }, - "openai/o4-mini-deep-research": { - id: "openai/o4-mini-deep-research", - name: "o4-mini-deep-research", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-06-27", - last_updated: "2025-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.8, output: 7.2, cache_read: 0.45 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-mini": { - id: "openai/gpt-5.4-mini", - name: "GPT-5.4-Mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-12", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.68, output: 4, cache_read: 0.068 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/dall-e-3": { - id: "openai/dall-e-3", - name: "DALL-E-3", - family: "dall-e", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-11-06", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 800, output: 0 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.99, output: 4, cache_read: 0.25 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-nano": { - id: "openai/gpt-5.4-nano", - name: "GPT-5.4-Nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 1.1, cache_read: 0.018 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-image-1": { - id: "openai/gpt-image-1", - name: "GPT-Image-1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-03-31", - last_updated: "2025-03-31", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 128000, output: 0 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2-Codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 13, cache_read: 0.16 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT-5.1-Codex-Mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-12", - last_updated: "2025-11-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.22, output: 1.8, cache_read: 0.022 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-12", - last_updated: "2025-11-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-image-1-mini": { - id: "openai/gpt-image-1-mini", - name: "GPT-Image-1-Mini", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "openai/o1": { - id: "openai/o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2024-12-18", - last_updated: "2024-12-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 14, output: 54 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "GPT-5.4-Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - cost: { input: 27, output: 160 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-3.5-turbo": { - id: "openai/gpt-3.5-turbo", - name: "GPT-3.5-Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-09-13", - last_updated: "2023-09-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 1.4 }, - limit: { context: 16384, output: 2048 }, - }, - "openai/o3-deep-research": { - id: "openai/o3-deep-research", - name: "o3-deep-research", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-06-27", - last_updated: "2025-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 9, output: 36, cache_read: 2.2 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.99, output: 4 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o1-pro": { - id: "openai/o1-pro", - name: "o1-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-03-19", - last_updated: "2025-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 140, output: 540 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o-search": { - id: "openai/gpt-4o-search", - name: "GPT-4o-Search", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-03-11", - last_updated: "2025-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.2, output: 9 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "pdf"], output: ["image"] }, - open_weights: false, - cost: { input: 2.2, output: 14, cache_read: 0.22 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5.3-codex-spark": { - id: "openai/gpt-5.3-codex-spark", - name: "GPT-5.3-Codex-Spark", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-03-04", - last_updated: "2026-03-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-3.5-turbo-raw": { - id: "openai/gpt-3.5-turbo-raw", - name: "GPT-3.5-Turbo-Raw", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-09-27", - last_updated: "2023-09-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 1.4 }, - limit: { context: 4524, output: 2048 }, - }, - "openai/gpt-4.1-nano": { - id: "openai/gpt-4.1-nano", - name: "GPT-4.1-nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.36, cache_read: 0.022 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/o3": { - id: "openai/o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.8, output: 7.2, cache_read: 0.45 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "GPT-5-Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 14, output: 110 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/sora-2": { - id: "openai/sora-2", - name: "Sora-2", - family: "sora", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-instant": { - id: "openai/gpt-5.2-instant", - name: "GPT-5.2-Instant", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 13, cache_read: 0.16 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4o-mini-search": { - id: "openai/gpt-4o-mini-search", - name: "GPT-4o-mini-Search", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-03-11", - last_updated: "2025-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.54 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-image-1.5": { - id: "openai/gpt-image-1.5", - name: "gpt-image-1.5", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 128000, output: 0 }, - }, - "openai/gpt-3.5-turbo-instruct": { - id: "openai/gpt-3.5-turbo-instruct", - name: "GPT-3.5-Turbo-Instruct", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2023-09-20", - last_updated: "2023-09-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 1.8 }, - limit: { context: 3500, output: 1024 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.8, output: 7.2, cache_read: 0.45 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5.1-instant": { - id: "openai/gpt-5.1-instant", - name: "GPT-5.1-Instant", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-12", - last_updated: "2025-11-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT-4.1-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.36, output: 1.4, cache_read: 0.09 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-4-classic": { - id: "openai/gpt-4-classic", - name: "GPT-4-Classic", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-03-25", - last_updated: "2024-03-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 27, output: 54 }, - limit: { context: 8192, output: 4096 }, - status: "deprecated", - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-12", - last_updated: "2025-11-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.3-instant": { - id: "openai/gpt-5.3-instant", - name: "GPT-5.3-Instant", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 13, cache_read: 0.16 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "google/veo-3-fast": { - id: "google/veo-3-fast", - name: "Veo-3-Fast", - family: "veo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-10-13", - last_updated: "2025-10-13", - modalities: { input: ["text"], output: ["video"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/veo-3.1-fast": { - id: "google/veo-3.1-fast", - name: "Veo-3.1-Fast", - family: "veo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-3.1-pro": { - id: "google/gemini-3.1-pro", - name: "Gemini-3.1-Pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/imagen-3-fast": { - id: "google/imagen-3-fast", - name: "Imagen-3-Fast", - family: "imagen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-10-17", - last_updated: "2024-10-17", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-2.0-flash": { - id: "google/gemini-2.0-flash", - name: "Gemini-2.0-Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.42 }, - limit: { context: 990000, output: 8192 }, - }, - "google/gemini-deep-research": { - id: "google/gemini-deep-research", - name: "gemini-deep-research", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 9.6 }, - limit: { context: 1048576, output: 0 }, - status: "deprecated", - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini-2.5-Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-02-05", - last_updated: "2025-02-05", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.87, output: 7, cache_read: 0.087 }, - limit: { context: 1065535, output: 65535 }, - }, - "google/imagen-3": { - id: "google/imagen-3", - name: "Imagen-3", - family: "imagen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-10-15", - last_updated: "2024-10-15", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/nano-banana": { - id: "google/nano-banana", - name: "Nano-Banana", - family: "nano-banana", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.21, output: 1.8, cache_read: 0.021 }, - limit: { context: 65536, output: 0 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini-2.5-Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-04-26", - last_updated: "2025-04-26", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 1.8, cache_read: 0.021 }, - limit: { context: 1065535, output: 65535 }, - }, - "google/gemini-3.1-flash-lite": { - id: "google/gemini-3.1-flash-lite", - name: "Gemini-3.1-Flash-Lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-18", - last_updated: "2026-02-18", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-flash": { - id: "google/gemini-3-flash", - name: "Gemini-3-Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-10-07", - last_updated: "2025-10-07", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4, cache_read: 0.04 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/veo-3.1": { - id: "google/veo-3.1", - name: "Veo-3.1", - family: "veo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text"], output: ["video"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/lyria": { - id: "google/lyria", - name: "Lyria", - family: "lyria", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-06-04", - last_updated: "2025-06-04", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "google/imagen-4-ultra": { - id: "google/imagen-4-ultra", - name: "Imagen-4-Ultra", - family: "imagen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-05-24", - last_updated: "2025-05-24", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/nano-banana-pro": { - id: "google/nano-banana-pro", - name: "Nano-Banana-Pro", - family: "nano-banana", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 65536, output: 0 }, - }, - "google/gemini-3-pro": { - id: "google/gemini-3-pro", - name: "Gemini-3-Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-10-22", - last_updated: "2025-10-22", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 9.6, cache_read: 0.16 }, - limit: { context: 1048576, output: 65536 }, - status: "deprecated", - }, - "google/imagen-4-fast": { - id: "google/imagen-4-fast", - name: "Imagen-4-Fast", - family: "imagen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-06-25", - last_updated: "2025-06-25", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/veo-3": { - id: "google/veo-3", - name: "Veo-3", - family: "veo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-05-21", - last_updated: "2025-05-21", - modalities: { input: ["text"], output: ["video"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-2.5-flash-lite": { - id: "google/gemini-2.5-flash-lite", - name: "Gemini-2.5-Flash-Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-06-19", - last_updated: "2025-06-19", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 1024000, output: 64000 }, - }, - "google/imagen-4": { - id: "google/imagen-4", - name: "Imagen-4", - family: "imagen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemma-4-31b": { - id: "google/gemma-4-31b", - name: "Gemma-4-31B", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 8192 }, - }, - "google/gemini-2.0-flash-lite": { - id: "google/gemini-2.0-flash-lite", - name: "Gemini-2.0-Flash-Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-02-05", - last_updated: "2025-02-05", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.052, output: 0.21 }, - limit: { context: 990000, output: 8192 }, - }, - "google/veo-2": { - id: "google/veo-2", - name: "Veo-2", - family: "veo", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-12-02", - last_updated: "2024-12-02", - modalities: { input: ["text"], output: ["video"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "lumalabs/ray2": { - id: "lumalabs/ray2", - name: "Ray2", - family: "ray", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-02-20", - last_updated: "2025-02-20", - modalities: { input: ["text", "image"], output: ["video"] }, - open_weights: false, - limit: { context: 5000, output: 0 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Claude-Opus-4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 13, output: 64, cache_read: 1.3, cache_write: 16 }, - limit: { context: 196608, output: 32000 }, - }, - "anthropic/claude-sonnet-3.5": { - id: "anthropic/claude-sonnet-3.5", - name: "Claude-Sonnet-3.5", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-06-05", - last_updated: "2024-06-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 189096, output: 8192 }, - status: "deprecated", - }, - "anthropic/claude-haiku-3": { - id: "anthropic/claude-haiku-3", - name: "Claude-Haiku-3", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-03-09", - last_updated: "2024-03-09", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 1.1, cache_read: 0.021, cache_write: 0.26 }, - limit: { context: 189096, output: 8192 }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Claude-Opus-4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-04", - last_updated: "2026-02-04", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.3, output: 21, cache_read: 0.43, cache_write: 5.3 }, - limit: { context: 983040, output: 128000 }, - }, - "anthropic/claude-opus-4.7": { - id: "anthropic/claude-opus-4.7", - name: "Claude-Opus-4.7", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-15", - last_updated: "2026-04-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.3, output: 21, cache_read: 0.43, cache_write: 5.4 }, - limit: { context: 1048576, output: 128000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude-Sonnet-4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-05-21", - last_updated: "2025-05-21", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 983040, output: 64000 }, - }, - "anthropic/claude-sonnet-4.5": { - id: "anthropic/claude-sonnet-4.5", - name: "Claude-Sonnet-4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-09-26", - last_updated: "2025-09-26", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 983040, output: 32768 }, - }, - "anthropic/claude-opus-4.5": { - id: "anthropic/claude-opus-4.5", - name: "Claude-Opus-4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-21", - last_updated: "2025-11-21", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 4.3, output: 21, cache_read: 0.43, cache_write: 5.3 }, - limit: { context: 196608, output: 64000 }, - }, - "anthropic/claude-sonnet-3.7": { - id: "anthropic/claude-sonnet-3.7", - name: "Claude-Sonnet-3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 196608, output: 128000 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude-Opus-4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-05-21", - last_updated: "2025-05-21", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 13, output: 64, cache_read: 1.3, cache_write: 16 }, - limit: { context: 192512, output: 28672 }, - }, - "anthropic/claude-haiku-3.5": { - id: "anthropic/claude-haiku-3.5", - name: "Claude-Haiku-3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.68, output: 3.4, cache_read: 0.068, cache_write: 0.85 }, - limit: { context: 189096, output: 8192 }, - }, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Claude-Haiku-4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.85, output: 4.3, cache_read: 0.085, cache_write: 1.1 }, - limit: { context: 192000, output: 64000 }, - }, - "anthropic/claude-sonnet-3.5-june": { - id: "anthropic/claude-sonnet-3.5-june", - name: "Claude-Sonnet-3.5-June", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-11-18", - last_updated: "2024-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 189096, output: 8192 }, - status: "deprecated", - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Claude-Sonnet-4.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.6, output: 13, cache_read: 0.26, cache_write: 3.2 }, - limit: { context: 983040, output: 128000 }, - }, - "ideogramai/ideogram": { - id: "ideogramai/ideogram", - name: "Ideogram", - family: "ideogram", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-04-03", - last_updated: "2024-04-03", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 150, output: 0 }, - }, - "ideogramai/ideogram-v2": { - id: "ideogramai/ideogram-v2", - name: "Ideogram-v2", - family: "ideogram", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-08-21", - last_updated: "2024-08-21", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 150, output: 0 }, - }, - "ideogramai/ideogram-v2a-turbo": { - id: "ideogramai/ideogram-v2a-turbo", - name: "Ideogram-v2a-Turbo", - family: "ideogram", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 150, output: 0 }, - }, - "ideogramai/ideogram-v2a": { - id: "ideogramai/ideogram-v2a", - name: "Ideogram-v2a", - family: "ideogram", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 150, output: 0 }, - }, - "trytako/tako": { - id: "trytako/tako", - name: "Tako", - family: "tako", - attachment: true, - reasoning: false, - tool_call: true, - temperature: false, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 2048, output: 0 }, - }, - "poetools/claude-code": { - id: "poetools/claude-code", - name: "claude-code", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2025-11-27", - last_updated: "2025-11-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 4.5455, output: 27.2727, cache_read: 0.4545 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.5-pro": { - id: "openai/gpt-5.5-pro", - name: "GPT-5.5-Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 27.2727, output: 163.6364 }, - limit: { context: 400000, output: 128000 }, - }, - }, - }, - helicone: { - id: "helicone", - env: ["HELICONE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://ai-gateway.helicone.ai/v1", - name: "Helicone", - doc: "https://helicone.ai/models", - models: { - "mistral-nemo": { - id: "mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 40 }, - limit: { context: 128000, output: 16400 }, - }, - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "xAI Grok 4.1 Fast Reasoning", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-17", - last_updated: "2025-11-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 0.5, cache_read: 0.049999999999999996 }, - limit: { context: 2000000, output: 2000000 }, - }, - "gemma2-9b-it": { - id: "gemma2-9b-it", - name: "Google Gemma 2", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-25", - last_updated: "2024-06-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.01, output: 0.03 }, - limit: { context: 8192, output: 8192 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Meta Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0.39 }, - limit: { context: 128000, output: 16400 }, - }, - "llama-4-scout": { - id: "llama-4-scout", - name: "Meta Llama 4 Scout 17B 16E", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.3 }, - limit: { context: 131072, output: 8192 }, - }, - "chatgpt-4o-latest": { - id: "chatgpt-4o-latest", - name: "OpenAI ChatGPT-4o", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-14", - last_updated: "2024-08-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 20, cache_read: 2.5 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-3.5-sonnet-v2": { - id: "claude-3.5-sonnet-v2", - name: "Anthropic: Claude 3.5 Sonnet v2", - family: "claude-sonnet", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.30000000000000004, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "hermes-2-pro-llama-3-8b": { - id: "hermes-2-pro-llama-3-8b", - name: "Hermes 2 Pro Llama 3 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-05", - release_date: "2024-05-27", - last_updated: "2024-05-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.14 }, - limit: { context: 131072, output: 131072 }, - }, - "claude-3.7-sonnet": { - id: "claude-3.7-sonnet", - name: "Anthropic: Claude 3.7 Sonnet", - family: "claude-sonnet", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-02", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.30000000000000004, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "llama-prompt-guard-2-22m": { - id: "llama-prompt-guard-2-22m", - name: "Meta Llama Prompt Guard 2 22M", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.01, output: 0.01 }, - limit: { context: 512, output: 2 }, - }, - "o1-mini": { - id: "o1-mini", - name: "OpenAI: o1-mini", - family: "o-mini", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 128000, output: 65536 }, - }, - "gpt-4.1-mini-2025-04-14": { - id: "gpt-4.1-mini-2025-04-14", - name: "OpenAI GPT-4.1 Mini", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39999999999999997, output: 1.5999999999999999, cache_read: 0.09999999999999999 }, - limit: { context: 1047576, output: 32768 }, - }, - "deepseek-r1-distill-llama-70b": { - id: "deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0.13 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 0.59 }, - limit: { context: 131072, output: 40960 }, - }, - "llama-3.3-70b-versatile": { - id: "llama-3.3-70b-versatile", - name: "Meta Llama 3.3 70B Versatile", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.7899999999999999 }, - limit: { context: 131072, output: 32678 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "OpenAI GPT-5 Mini", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.024999999999999998 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "OpenAI GPT-5 Nano", - family: "gpt-nano", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049999999999999996, output: 0.39999999999999997, cache_read: 0.005 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Google Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.19999999999999998 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-3-haiku-20240307": { - id: "claude-3-haiku-20240307", - name: "Anthropic: Claude 3 Haiku", - family: "claude-haiku", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-03-07", - last_updated: "2024-03-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "llama-4-maverick": { - id: "llama-4-maverick", - name: "Meta Llama 4 Maverick 17B 128E", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 8192 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Anthropic: Claude Sonnet 4.5 (20250929)", - family: "claude-sonnet", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.30000000000000004, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Google Gemini 2.5 Pro", - family: "gemini-pro", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.3125, cache_write: 1.25 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-4.5-opus": { - id: "claude-4.5-opus", - name: "Anthropic: Claude Opus 4.5", - family: "claude-opus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "xAI Grok 4.1 Fast Non-Reasoning", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-17", - last_updated: "2025-11-17", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 0.5, cache_read: 0.049999999999999996 }, - limit: { context: 2000000, output: 30000 }, - }, - "sonar-pro": { - id: "sonar-pro", - name: "Perplexity Sonar Pro", - family: "sonar-pro", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 4096 }, - }, - "mistral-large-2411": { - id: "mistral-large-2411", - name: "Mistral-Large", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-24", - last_updated: "2024-07-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 32768 }, - }, - "o3-pro": { - id: "o3-pro", - name: "OpenAI o3 Pro", - family: "o-pro", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 80 }, - limit: { context: 200000, output: 100000 }, - }, - "claude-opus-4-1": { - id: "claude-opus-4-1", - name: "Anthropic: Claude Opus 4.1", - family: "claude-opus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "OpenAI GPT-4o-mini", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.075 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-4.5-haiku": { - id: "claude-4.5-haiku", - name: "Anthropic: Claude 4.5 Haiku", - family: "claude-haiku", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-10", - release_date: "2025-10-01", - last_updated: "2025-10-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.09999999999999999, cache_write: 1.25 }, - limit: { context: 200000, output: 8192 }, - }, - "kimi-k2-0711": { - id: "kimi-k2-0711", - name: "Kimi K2 (07/11)", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5700000000000001, output: 2.3 }, - limit: { context: 131072, output: 16384 }, - }, - "o4-mini": { - id: "o4-mini", - name: "OpenAI o4 Mini", - family: "o-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.275 }, - limit: { context: 200000, output: 100000 }, - }, - "sonar-deep-research": { - id: "sonar-deep-research", - name: "Perplexity Sonar Deep Research", - family: "sonar-deep-research", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 127000, output: 4096 }, - }, - "gemma-3-12b-it": { - id: "gemma-3-12b-it", - name: "Google Gemma 3 12B", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049999999999999996, output: 0.09999999999999999 }, - limit: { context: 131072, output: 8192 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Google Gemini 2.5 Flash", - family: "gemini-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, cache_write: 0.3 }, - limit: { context: 1048576, output: 65535 }, - }, - "deepseek-tng-r1t2-chimera": { - id: "deepseek-tng-r1t2-chimera", - name: "DeepSeek TNG R1T2 Chimera", - family: "deepseek-thinking", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-02", - last_updated: "2025-07-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 130000, output: 163840 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "OpenAI: GPT-5.1 Codex Mini", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.024999999999999998 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-sonnet-4": { - id: "claude-sonnet-4", - name: "Anthropic: Claude Sonnet 4", - family: "claude-sonnet", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-14", - last_updated: "2025-05-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.30000000000000004, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "xAI Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-25", - last_updated: "2024-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "OpenAI GPT-5.1", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 400000, output: 128000 }, - }, - "deepseek-reasoner": { - id: "deepseek-reasoner", - name: "DeepSeek Reasoner", - family: "deepseek-thinking", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 1.68, cache_read: 0.07 }, - limit: { context: 128000, output: 64000 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "xAI: Grok 4 Fast Reasoning", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 0.5, cache_read: 0.049999999999999996 }, - limit: { context: 2000000, output: 2000000 }, - }, - o1: { - id: "o1", - name: "OpenAI: o1", - family: "o", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "llama-3.1-8b-instant": { - id: "llama-3.1-8b-instant", - name: "Meta Llama 3.1 8B Instant", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049999999999999996, output: 0.08 }, - limit: { context: 131072, output: 32678 }, - }, - "o3-mini": { - id: "o3-mini", - name: "OpenAI o3 Mini", - family: "o-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2023-10", - release_date: "2023-10-01", - last_updated: "2023-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - sonar: { - id: "sonar", - name: "Perplexity Sonar", - family: "sonar", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 127000, output: 4096 }, - }, - "kimi-k2-0905": { - id: "kimi-k2-0905", - name: "Kimi K2 (09/05)", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2, cache_read: 0.39999999999999997 }, - limit: { context: 262144, output: 16384 }, - }, - "mistral-small": { - id: "mistral-small", - name: "Mistral Small", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-02", - release_date: "2024-02-26", - last_updated: "2024-02-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 75, output: 200 }, - limit: { context: 128000, output: 128000 }, - }, - "qwen3-30b-a3b": { - id: "qwen3-30b-a3b", - name: "Qwen3 30B A3B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.29 }, - limit: { context: 41000, output: 41000 }, - }, - "grok-4": { - id: "grok-4", - name: "xAI Grok 4", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-09", - last_updated: "2024-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 256000 }, - }, - "qwen3-235b-a22b-thinking": { - id: "qwen3-235b-a22b-thinking", - name: "Qwen3 235B A22B Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.9000000000000004 }, - limit: { context: 262144, output: 81920 }, - }, - "qwen2.5-coder-7b-fast": { - id: "qwen2.5-coder-7b-fast", - name: "Qwen2.5 Coder 7B fast", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-09", - release_date: "2024-09-15", - last_updated: "2024-09-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0.09 }, - limit: { context: 32000, output: 8192 }, - }, - "llama-3.1-8b-instruct-turbo": { - id: "llama-3.1-8b-instruct-turbo", - name: "Meta Llama 3.1 8B Instruct Turbo", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.03 }, - limit: { context: 128000, output: 128000 }, - }, - "qwen3-next-80b-a3b-instruct": { - id: "qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262000, output: 16384 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "Zai GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.44999999999999996, output: 1.5 }, - limit: { context: 204800, output: 131072 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "OpenAI: GPT-5 Codex", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "Anthropic: Claude Opus 4.1 (20250805)", - family: "claude-opus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-5.1-chat-latest": { - id: "gpt-5.1-chat-latest", - name: "OpenAI GPT-5.1 Chat", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Anthropic: Claude 4.5 Haiku (20251001)", - family: "claude-haiku", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-10", - release_date: "2025-10-01", - last_updated: "2025-10-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.09999999999999999, cache_write: 1.25 }, - limit: { context: 200000, output: 8192 }, - }, - "sonar-reasoning": { - id: "sonar-reasoning", - name: "Perplexity Sonar Reasoning", - family: "sonar-reasoning", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 127000, output: 4096 }, - }, - "claude-opus-4": { - id: "claude-opus-4", - name: "Anthropic: Claude Opus 4", - family: "claude-opus", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-14", - last_updated: "2025-05-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "llama-prompt-guard-2-86m": { - id: "llama-prompt-guard-2-86m", - name: "Meta Llama Prompt Guard 2 86M", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.01, output: 0.01 }, - limit: { context: 512, output: 2 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "OpenAI GPT-4.1 Nano", - family: "gpt-nano", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09999999999999999, output: 0.39999999999999997, cache_read: 0.024999999999999998 }, - limit: { context: 1047576, output: 32768 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09999999999999999, output: 0.3 }, - limit: { context: 262144, output: 262144 }, - }, - "claude-3.5-haiku": { - id: "claude-3.5-haiku", - name: "Anthropic: Claude 3.5 Haiku", - family: "claude-haiku", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7999999999999999, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "grok-3-mini": { - id: "grok-3-mini", - name: "xAI Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 131072 }, - }, - o3: { - id: "o3", - name: "OpenAI o3", - family: "o", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 163840, output: 65536 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "OpenAI GPT-OSS 20b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049999999999999996, output: 0.19999999999999998 }, - limit: { context: 131072, output: 131072 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "OpenAI: GPT-5 Pro", - family: "gpt-pro", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 128000, output: 32768 }, - }, - "llama-guard-4": { - id: "llama-guard-4", - name: "Meta Llama Guard 4 12B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.21 }, - limit: { context: 131072, output: 1024 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "OpenAI GPT-4o", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-05", - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-vl-235b-a22b-instruct": { - id: "qwen3-vl-235b-a22b-instruct", - name: "Qwen3 VL 235B A22B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 256000, output: 16384 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Google Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.09999999999999999, - output: 0.39999999999999997, - cache_read: 0.024999999999999998, - cache_write: 0.09999999999999999, - }, - limit: { context: 1048576, output: 65535 }, - }, - "qwen3-coder": { - id: "qwen3-coder", - name: "Qwen3 Coder 480B A35B Instruct Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.22, output: 0.95 }, - limit: { context: 262144, output: 16384 }, - }, - "gpt-5": { - id: "gpt-5", - name: "OpenAI GPT-5", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 400000, output: 128000 }, - }, - "ernie-4.5-21b-a3b-thinking": { - id: "ernie-4.5-21b-a3b-thinking", - name: "Baidu Ernie 4.5 21B A3B Thinking", - family: "ernie", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-03", - release_date: "2025-03-16", - last_updated: "2025-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 128000, output: 8000 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "OpenAI GPT-OSS 120b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.16 }, - limit: { context: 131072, output: 131072 }, - }, - "gpt-5-chat-latest": { - id: "gpt-5-chat-latest", - name: "OpenAI GPT-5 Chat Latest", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2024-09", - release_date: "2024-09-30", - last_updated: "2024-09-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-4.5-sonnet": { - id: "claude-4.5-sonnet", - name: "Anthropic: Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.30000000000000004, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "deepseek-v3": { - id: "deepseek-v3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-26", - last_updated: "2024-12-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 1.68, cache_read: 0.07 }, - limit: { context: 128000, output: 8192 }, - }, - "llama-3.1-8b-instruct": { - id: "llama-3.1-8b-instruct", - name: "Meta Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0.049999999999999996 }, - limit: { context: 16384, output: 16384 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "OpenAI GPT-4.1", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.48, output: 2 }, - limit: { context: 256000, output: 262144 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "OpenAI GPT-4.1 Mini", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39999999999999997, output: 1.5999999999999999, cache_read: 0.09999999999999999 }, - limit: { context: 1047576, output: 32768 }, - }, - "deepseek-v3.1-terminus": { - id: "deepseek-v3.1-terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1, cache_read: 0.21600000000000003 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "OpenAI: GPT-5.1 Codex", - family: "gpt-codex", - attachment: false, - reasoning: false, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.12500000000000003 }, - limit: { context: 400000, output: 128000 }, - }, - "grok-3": { - id: "grok-3", - name: "xAI Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 131072 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "xAI Grok 4 Fast Non-Reasoning", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 0.5, cache_read: 0.049999999999999996 }, - limit: { context: 2000000, output: 2000000 }, - }, - "sonar-reasoning-pro": { - id: "sonar-reasoning-pro", - name: "Perplexity Sonar Reasoning Pro", - family: "sonar-reasoning", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-27", - last_updated: "2025-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 127000, output: 4096 }, - }, - }, - }, - "ollama-cloud": { - id: "ollama-cloud", - env: ["OLLAMA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://ollama.com/v1", - name: "Ollama Cloud", - doc: "https://docs.ollama.com/cloud", - models: { - "minimax-m2.7": { - id: "minimax-m2.7", - name: "minimax-m2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 196608, output: 196608 }, - }, - "gpt-oss:20b": { - id: "gpt-oss:20b", - name: "gpt-oss:20b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-08-05", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 32768 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "kimi-k2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "glm-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-12-22", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 202752, output: 131072 }, - }, - "gemma4:31b": { - id: "gemma4:31b", - name: "gemma4:31b", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - knowledge: "2025-01", - release_date: "2026-04-02", - last_updated: "2026-04-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "gpt-oss:120b": { - id: "gpt-oss:120b", - name: "gpt-oss:120b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-08-05", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 32768 }, - }, - "qwen3.5:397b": { - id: "qwen3.5:397b", - name: "qwen3.5:397b", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - release_date: "2026-02-15", - last_updated: "2026-02-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 65536 }, - }, - "deepseek-v3.1:671b": { - id: "deepseek-v3.1:671b", - name: "deepseek-v3.1:671b", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-08-21", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 163840, output: 163840 }, - }, - "glm-5": { - id: "glm-5", - name: "glm-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 202752, output: 131072 }, - }, - "qwen3-vl:235b-instruct": { - id: "qwen3-vl:235b-instruct", - name: "qwen3-vl:235b-instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2025-09-22", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 131072 }, - }, - "gemma3:4b": { - id: "gemma3:4b", - name: "gemma3:4b", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - release_date: "2024-12-01", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 131072 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "gemini-3-flash-preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2026-04-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 1048576, output: 65536 }, - }, - "ministral-3:14b": { - id: "ministral-3:14b", - name: "ministral-3:14b", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2024-12-01", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 128000 }, - }, - "minimax-m2": { - id: "minimax-m2", - name: "minimax-m2", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-10-23", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 204800, output: 128000 }, - }, - "qwen3-next:80b": { - id: "qwen3-next:80b", - name: "qwen3-next:80b", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-09-15", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 32768 }, - }, - "qwen3-vl:235b": { - id: "qwen3-vl:235b", - name: "qwen3-vl:235b", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2025-09-22", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 32768 }, - }, - "rnj-1:8b": { - id: "rnj-1:8b", - name: "rnj-1:8b", - family: "rnj", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-12-06", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 32768, output: 4096 }, - }, - "minimax-m2.1": { - id: "minimax-m2.1", - name: "minimax-m2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-12-23", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 204800, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "glm-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - release_date: "2026-03-27", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 202752, output: 131072 }, - }, - "mistral-large-3:675b": { - id: "mistral-large-3:675b", - name: "mistral-large-3:675b", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2025-12-02", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "ministral-3:8b": { - id: "ministral-3:8b", - name: "ministral-3:8b", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2024-12-01", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 128000 }, - }, - "gemma3:12b": { - id: "gemma3:12b", - name: "gemma3:12b", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - release_date: "2024-12-01", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 131072 }, - }, - "qwen3-coder:480b": { - id: "qwen3-coder:480b", - name: "qwen3-coder:480b", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-07-22", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 65536 }, - }, - "kimi-k2.6:cloud": { - id: "kimi-k2.6:cloud", - name: "kimi-k2.6:cloud", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "nemotron-3-nano:30b": { - id: "nemotron-3-nano:30b", - name: "nemotron-3-nano:30b", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-12-15", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 1048576, output: 131072 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "deepseek-v4-flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 1048576, output: 1048576 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "glm-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-09-29", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 202752, output: 131072 }, - }, - "ministral-3:3b": { - id: "ministral-3:3b", - name: "ministral-3:3b", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2024-10-22", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 128000 }, - }, - "gemma3:27b": { - id: "gemma3:27b", - name: "gemma3:27b", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - release_date: "2025-07-27", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 131072 }, - }, - "devstral-2:123b": { - id: "devstral-2:123b", - name: "devstral-2:123b", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-12-09", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "cogito-2.1:671b": { - id: "cogito-2.1:671b", - name: "cogito-2.1:671b", - family: "cogito", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-11-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 163840, output: 32000 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "qwen3-coder-next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2026-02-02", - last_updated: "2026-02-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 65536 }, - }, - "nemotron-3-super": { - id: "nemotron-3-super", - name: "nemotron-3-super", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2026-03-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 65536 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "deepseek-v4-pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 1048576, output: 1048576 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "minimax-m2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - knowledge: "2025-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 204800, output: 131072 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "deepseek-v3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-06-15", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 163840, output: 65536 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "kimi-k2-thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "devstral-small-2:24b": { - id: "devstral-small-2:24b", - name: "devstral-small-2:24b", - family: "devstral", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2025-12-09", - last_updated: "2026-01-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2:1t": { - id: "kimi-k2:1t", - name: "kimi-k2:1t", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - knowledge: "2024-10", - release_date: "2025-07-11", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - "zai-coding-plan": { - id: "zai-coding-plan", - env: ["ZHIPU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.z.ai/api/coding/paas/v4", - name: "Z.AI Coding Plan", - doc: "https://docs.z.ai/devpack/overview", - models: { - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-5-turbo": { - id: "glm-5-turbo", - name: "GLM-5-Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - }, - }, - "amazon-bedrock": { - id: "amazon-bedrock", - env: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION", "AWS_BEARER_TOKEN_BEDROCK"], - npm: "@ai-sdk/amazon-bedrock", - name: "Amazon Bedrock", - doc: "https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html", - models: { - "openai.gpt-oss-safeguard-120b": { - id: "openai.gpt-oss-safeguard-120b", - name: "GPT OSS Safeguard 120B", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia.nemotron-nano-3-30b": { - id: "nvidia.nemotron-nano-3-30b", - name: "NVIDIA Nemotron Nano 3 30B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.24 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia.nemotron-super-3-120b": { - id: "nvidia.nemotron-super-3-120b", - name: "NVIDIA Nemotron 3 Super 120B A12B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.65 }, - limit: { context: 262144, output: 131072 }, - }, - "writer.palmyra-x5-v1:0": { - id: "writer.palmyra-x5-v1:0", - name: "Palmyra X5", - family: "palmyra", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 6 }, - limit: { context: 1040000, output: 8192 }, - }, - "mistral.ministral-3-8b-instruct": { - id: "mistral.ministral-3-8b-instruct", - name: "Ministral 3 8B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 4096 }, - }, - "au.anthropic.claude-opus-4-6-v1": { - id: "au.anthropic.claude-opus-4-6-v1", - name: "AU Anthropic Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 16.5, output: 82.5, cache_read: 1.65, cache_write: 20.625 }, - limit: { context: 1000000, output: 128000 }, - }, - "mistral.ministral-3-3b-instruct": { - id: "mistral.ministral-3-3b-instruct", - name: "Ministral 3 3B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 256000, output: 8192 }, - }, - "anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "mistral.devstral-2-123b": { - id: "mistral.devstral-2-123b", - name: "Devstral 2 123B", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 256000, output: 8192 }, - }, - "global.anthropic.claude-opus-4-5-20251101-v1:0": { - id: "global.anthropic.claude-opus-4-5-20251101-v1:0", - name: "Claude Opus 4.5 (Global)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "mistral.voxtral-small-24b-2507": { - id: "mistral.voxtral-small-24b-2507", - name: "Voxtral Small 24B 2507", - family: "mistral", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-01", - last_updated: "2025-07-01", - modalities: { input: ["text", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.35 }, - limit: { context: 32000, output: 8192 }, - }, - "google.gemma-3-12b-it": { - id: "google.gemma-3-12b-it", - name: "Google Gemma 3 12B", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.049999999999999996, output: 0.09999999999999999 }, - limit: { context: 131072, output: 8192 }, - }, - "amazon.nova-pro-v1:0": { - id: "amazon.nova-pro-v1:0", - name: "Nova Pro", - family: "nova-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2, cache_read: 0.2 }, - limit: { context: 300000, output: 8192 }, - }, - "anthropic.claude-haiku-4-5-20251001-v1:0": { - id: "anthropic.claude-haiku-4-5-20251001-v1:0", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "minimax.minimax-m2": { - id: "minimax.minimax-m2", - name: "MiniMax M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204608, output: 128000 }, - }, - "global.anthropic.claude-opus-4-7": { - id: "global.anthropic.claude-opus-4-7", - name: "Claude Opus 4.7 (Global)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "mistral.pixtral-large-2502-v1:0": { - id: "mistral.pixtral-large-2502-v1:0", - name: "Pixtral Large (25.02)", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-08", - last_updated: "2025-04-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 8192 }, - }, - "meta.llama4-maverick-17b-instruct-v1:0": { - id: "meta.llama4-maverick-17b-instruct-v1:0", - name: "Llama 4 Maverick 17B Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.97 }, - limit: { context: 1000000, output: 16384 }, - }, - "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "us.anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5 (US)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "us.anthropic.claude-haiku-4-5-20251001-v1:0": { - id: "us.anthropic.claude-haiku-4-5-20251001-v1:0", - name: "Claude Haiku 4.5 (US)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "amazon.nova-micro-v1:0": { - id: "amazon.nova-micro-v1:0", - name: "Nova Micro", - family: "nova-micro", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.035, output: 0.14, cache_read: 0.00875 }, - limit: { context: 128000, output: 8192 }, - }, - "global.anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "global.anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5 (Global)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "openai.gpt-oss-20b-1:0": { - id: "openai.gpt-oss-20b-1:0", - name: "gpt-oss-20b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.3 }, - limit: { context: 128000, output: 4096 }, - }, - "zai.glm-5": { - id: "zai.glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 202752, output: 101376 }, - }, - "qwen.qwen3-32b-v1:0": { - id: "qwen.qwen3-32b-v1:0", - name: "Qwen3 32B (dense)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 16384, output: 16384 }, - }, - "deepseek.v3.2": { - id: "deepseek.v3.2", - name: "DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.62, output: 1.85 }, - limit: { context: 163840, output: 81920 }, - }, - "eu.anthropic.claude-haiku-4-5-20251001-v1:0": { - id: "eu.anthropic.claude-haiku-4-5-20251001-v1:0", - name: "Claude Haiku 4.5 (EU)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "zai.glm-4.7-flash": { - id: "zai.glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4 }, - limit: { context: 200000, output: 131072 }, - }, - "us.anthropic.claude-opus-4-7": { - id: "us.anthropic.claude-opus-4-7", - name: "Claude Opus 4.7 (US)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "amazon.nova-2-lite-v1:0": { - id: "amazon.nova-2-lite-v1:0", - name: "Nova 2 Lite", - family: "nova", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.33, output: 2.75 }, - limit: { context: 128000, output: 4096 }, - }, - "anthropic.claude-opus-4-5-20251101-v1:0": { - id: "anthropic.claude-opus-4-5-20251101-v1:0", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen.qwen3-coder-480b-a35b-v1:0": { - id: "qwen.qwen3-coder-480b-a35b-v1:0", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 1.8 }, - limit: { context: 131072, output: 65536 }, - }, - "amazon.nova-lite-v1:0": { - id: "amazon.nova-lite-v1:0", - name: "Nova Lite", - family: "nova-lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.24, cache_read: 0.015 }, - limit: { context: 300000, output: 8192 }, - }, - "meta.llama3-1-8b-instruct-v1:0": { - id: "meta.llama3-1-8b-instruct-v1:0", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.22 }, - limit: { context: 128000, output: 4096 }, - }, - "anthropic.claude-opus-4-7": { - id: "anthropic.claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "google.gemma-3-27b-it": { - id: "google.gemma-3-27b-it", - name: "Google Gemma 3 27B Instruct", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-27", - last_updated: "2025-07-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.2 }, - limit: { context: 202752, output: 8192 }, - }, - "global.anthropic.claude-haiku-4-5-20251001-v1:0": { - id: "global.anthropic.claude-haiku-4-5-20251001-v1:0", - name: "Claude Haiku 4.5 (Global)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "google.gemma-3-4b-it": { - id: "google.gemma-3-4b-it", - name: "Gemma 3 4B IT", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.08 }, - limit: { context: 128000, output: 4096 }, - }, - "meta.llama4-scout-17b-instruct-v1:0": { - id: "meta.llama4-scout-17b-instruct-v1:0", - name: "Llama 4 Scout 17B Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.66 }, - limit: { context: 3500000, output: 16384 }, - }, - "deepseek.v3-v1:0": { - id: "deepseek.v3-v1:0", - name: "DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 1.68 }, - limit: { context: 163840, output: 81920 }, - }, - "mistral.magistral-small-2509": { - id: "mistral.magistral-small-2509", - name: "Magistral Small 1.2", - family: "magistral", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 128000, output: 40000 }, - }, - "qwen.qwen3-next-80b-a3b": { - id: "qwen.qwen3-next-80b-a3b", - name: "Qwen/Qwen3-Next-80B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262000, output: 262000 }, - }, - "zai.glm-4.7": { - id: "zai.glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 204800, output: 131072 }, - }, - "moonshot.kimi-k2-thinking": { - id: "moonshot.kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 256000, output: 256000 }, - }, - "us.anthropic.claude-opus-4-5-20251101-v1:0": { - id: "us.anthropic.claude-opus-4-5-20251101-v1:0", - name: "Claude Opus 4.5 (US)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "mistral.ministral-3-14b-instruct": { - id: "mistral.ministral-3-14b-instruct", - name: "Ministral 14B 3.0", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek.r1-v1:0": { - id: "deepseek.r1-v1:0", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral.voxtral-mini-3b-2507": { - id: "mistral.voxtral-mini-3b-2507", - name: "Voxtral Mini 3B 2507", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["audio", "text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 128000, output: 4096 }, - }, - "openai.gpt-oss-120b-1:0": { - id: "openai.gpt-oss-120b-1:0", - name: "gpt-oss-120b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia.nemotron-nano-12b-v2": { - id: "nvidia.nemotron-nano-12b-v2", - name: "NVIDIA Nemotron Nano 12B v2 VL BF16", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "eu.anthropic.claude-opus-4-7": { - id: "eu.anthropic.claude-opus-4-7", - name: "Claude Opus 4.7 (EU)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "minimax.minimax-m2.5": { - id: "minimax.minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196608, output: 98304 }, - }, - "meta.llama3-3-70b-instruct-v1:0": { - id: "meta.llama3-3-70b-instruct-v1:0", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 128000, output: 4096 }, - }, - "meta.llama3-1-70b-instruct-v1:0": { - id: "meta.llama3-1-70b-instruct-v1:0", - name: "Llama 3.1 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 128000, output: 4096 }, - }, - "eu.anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5 (EU)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "eu.anthropic.claude-opus-4-5-20251101-v1:0": { - id: "eu.anthropic.claude-opus-4-5-20251101-v1:0", - name: "Claude Opus 4.5 (EU)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "moonshotai.kimi-k2.5": { - id: "moonshotai.kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 256000, output: 256000 }, - }, - "au.anthropic.claude-sonnet-4-6": { - id: "au.anthropic.claude-sonnet-4-6", - name: "AU Anthropic Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3.3, output: 16.5, cache_read: 0.33, cache_write: 4.125 }, - limit: { context: 1000000, output: 128000 }, - }, - "openai.gpt-oss-safeguard-20b": { - id: "openai.gpt-oss-safeguard-20b", - name: "GPT OSS Safeguard 20B", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.2 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen.qwen3-coder-30b-a3b-v1:0": { - id: "qwen.qwen3-coder-30b-a3b-v1:0", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 262144, output: 131072 }, - }, - "minimax.minimax-m2.1": { - id: "minimax.minimax-m2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen.qwen3-vl-235b-a22b": { - id: "qwen.qwen3-vl-235b-a22b", - name: "Qwen/Qwen3-VL-235B-A22B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 262000, output: 262000 }, - }, - "qwen.qwen3-coder-next": { - id: "qwen.qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 1.8 }, - limit: { context: 131072, output: 65536 }, - }, - "nvidia.nemotron-nano-9b-v2": { - id: "nvidia.nemotron-nano-9b-v2", - name: "NVIDIA Nemotron Nano 9B v2", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.23 }, - limit: { context: 128000, output: 4096 }, - }, - "mistral.mistral-large-3-675b-instruct": { - id: "mistral.mistral-large-3-675b-instruct", - name: "Mistral Large 3", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 256000, output: 8192 }, - }, - "qwen.qwen3-235b-a22b-2507-v1:0": { - id: "qwen.qwen3-235b-a22b-2507-v1:0", - name: "Qwen3 235B A22B 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-18", - last_updated: "2025-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.88 }, - limit: { context: 262144, output: 131072 }, - }, - "writer.palmyra-x4-v1:0": { - id: "writer.palmyra-x4-v1:0", - name: "Palmyra X4", - family: "palmyra", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 122880, output: 8192 }, - }, - "anthropic.claude-opus-4-1-20250805-v1:0": { - id: "anthropic.claude-opus-4-1-20250805-v1:0", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "us.deepseek.r1-v1:0": { - id: "us.deepseek.r1-v1:0", - name: "DeepSeek-R1 (US)", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 128000, output: 32768 }, - }, - "eu.anthropic.claude-opus-4-6-v1": { - id: "eu.anthropic.claude-opus-4-6-v1", - name: "Claude Opus 4.6 (EU)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "us.meta.llama4-maverick-17b-instruct-v1:0": { - id: "us.meta.llama4-maverick-17b-instruct-v1:0", - name: "Llama 4 Maverick 17B Instruct (US)", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.97 }, - limit: { context: 1000000, output: 16384 }, - }, - "au.anthropic.claude-haiku-4-5-20251001-v1:0": { - id: "au.anthropic.claude-haiku-4-5-20251001-v1:0", - name: "Claude Haiku 4.5 (AU)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "jp.anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "jp.anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5 (JP)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic.claude-sonnet-4-6": { - id: "anthropic.claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "jp.anthropic.claude-sonnet-4-6": { - id: "jp.anthropic.claude-sonnet-4-6", - name: "Claude Sonnet 4.6 (JP)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "global.anthropic.claude-sonnet-4-6": { - id: "global.anthropic.claude-sonnet-4-6", - name: "Claude Sonnet 4.6 (Global)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "us.anthropic.claude-sonnet-4-6": { - id: "us.anthropic.claude-sonnet-4-6", - name: "Claude Sonnet 4.6 (US)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "global.anthropic.claude-opus-4-6-v1": { - id: "global.anthropic.claude-opus-4-6-v1", - name: "Claude Opus 4.6 (Global)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "us.anthropic.claude-opus-4-6-v1": { - id: "us.anthropic.claude-opus-4-6-v1", - name: "Claude Opus 4.6 (US)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "us.anthropic.claude-opus-4-1-20250805-v1:0": { - id: "us.anthropic.claude-opus-4-1-20250805-v1:0", - name: "Claude Opus 4.1 (US)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "au.anthropic.claude-sonnet-4-5-20250929-v1:0": { - id: "au.anthropic.claude-sonnet-4-5-20250929-v1:0", - name: "Claude Sonnet 4.5 (AU)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "eu.anthropic.claude-sonnet-4-6": { - id: "eu.anthropic.claude-sonnet-4-6", - name: "Claude Sonnet 4.6 (EU)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "us.meta.llama4-scout-17b-instruct-v1:0": { - id: "us.meta.llama4-scout-17b-instruct-v1:0", - name: "Llama 4 Scout 17B Instruct (US)", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.66 }, - limit: { context: 3500000, output: 16384 }, - }, - "anthropic.claude-opus-4-6-v1": { - id: "anthropic.claude-opus-4-6-v1", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "jp.anthropic.claude-opus-4-7": { - id: "jp.anthropic.claude-opus-4-7", - name: "Claude Opus 4.7 (JP)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - }, - }, - "the-grid-ai": { - id: "the-grid-ai", - env: ["THEGRIDAI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.thegrid.ai/v1", - name: "The Grid AI", - doc: "https://thegrid.ai/docs", - models: { - "text-prime": { - id: "text-prime", - name: "Text Prime", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 30000 }, - status: "beta", - }, - "text-standard": { - id: "text-standard", - name: "Text Standard", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 16000 }, - status: "beta", - }, - "text-max": { - id: "text-max", - name: "Text Max", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-24", - last_updated: "2026-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 1000000, output: 128000 }, - status: "beta", - }, - }, - }, - baseten: { - id: "baseten", - env: ["BASETEN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://inference.baseten.co/v1", - name: "Baseten", - doc: "https://docs.baseten.co/development/model-apis/overview", - models: { - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 204800, output: 131072 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 3.15 }, - limit: { context: 202752, output: 131072 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2025-09-16", - last_updated: "2025-09-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 200000, output: 200000 }, - }, - "nvidia/Nemotron-120B-A12B": { - id: "nvidia/Nemotron-120B-A12B", - name: "Nemotron 3 Super", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2026-02", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.75 }, - limit: { context: 262144, output: 32678 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-25", - last_updated: "2025-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 164000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-V3-0324": { - id: "deepseek-ai/DeepSeek-V3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.77, output: 0.77 }, - limit: { context: 164000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-10", - release_date: "2025-12-01", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.45 }, - limit: { context: 163800, output: 131100 }, - status: "deprecated", - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 128000, output: 128000 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - status: "deprecated", - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 Instruct 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-09-05", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - status: "deprecated", - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-12", - release_date: "2026-01-30", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 8192 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204000, output: 204000 }, - }, - "deepseek-ai/DeepSeek-V4-Pro": { - id: "deepseek-ai/DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.15 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - frogbot: { - id: "frogbot", - env: ["FROGBOT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://app.frogbot.ai/api/v1", - name: "FrogBot", - doc: "https://docs.frogbot.ai", - models: { - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "Grok 4.1 Fast (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 128000 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi-K2.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "1970-01-01", - last_updated: "1970-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 256000, output: 128000 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 128000 }, - }, - "zai-glm-5-1": { - id: "zai-glm-5-1", - name: "Z.AI GLM-5.1", - family: "glm", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-01-20", - last_updated: "2025-02-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 198000, output: 8192 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 128000 }, - }, - "gpt-5-4-nano": { - id: "gpt-5-4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-07-17", - last_updated: "2025-07-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075 }, - limit: { context: 1048576, output: 65536 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok 4.1 Fast (Reasoning)", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 128000 }, - }, - "gpt-5-5": { - id: "gpt-5-5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 272000, output: 128000 }, - }, - "grok-4-3": { - id: "grok-4-3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-11", - release_date: "2026-04-30", - last_updated: "2026-04-30", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 2.5, cache_read: 0.2 }, - limit: { context: 1000000, output: 128000 }, - }, - "gpt-5-4-mini": { - id: "gpt-5-4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 128000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek v4 Pro", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.74, output: 3.48, cache_read: 0.14 }, - limit: { context: 128000, output: 8192 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "1970-01-01", - last_updated: "1970-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.2 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen-3-6-plus": { - id: "qwen-3-6-plus", - name: "Qwen 3.6 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.1 }, - limit: { context: 1000000, output: 64000 }, - }, - "minimax-m2-7": { - id: "minimax-m2-7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 192000, output: 8192 }, - }, - "minimax-m2-5": { - id: "minimax-m2-5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-01-15", - last_updated: "2025-02-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03 }, - limit: { context: 192000, output: 8192 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "1970-01-01", - last_updated: "1970-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 32768 }, - }, - "gemini-3-1-pro-preview": { - id: "gemini-3-1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-18", - last_updated: "2026-02-18", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 1000000, output: 64000 }, - }, - "kimi-k2-6": { - id: "kimi-k2-6", - name: "Kimi-K2.6", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "1970-01-01", - last_updated: "1970-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 256000, output: 128000 }, - }, - "gpt-5-3-codex": { - id: "gpt-5-3-codex", - name: "GPT-5.3 Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - }, - }, - "zhipuai-coding-plan": { - id: "zhipuai-coding-plan", - env: ["ZHIPU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://open.bigmodel.cn/api/coding/paas/v4", - name: "Zhipu AI Coding Plan", - doc: "https://docs.bigmodel.cn/cn/coding-plan/overview", - models: { - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-5-turbo": { - id: "glm-5-turbo", - name: "GLM-5-Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - "alibaba-coding-plan": { - id: "alibaba-coding-plan", - env: ["ALIBABA_CODING_PLAN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://coding-intl.dashscope.aliyuncs.com/v1", - name: "Alibaba Coding Plan", - doc: "https://www.alibabacloud.com/help/en/model-studio/coding-plan", - models: { - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 16384 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 16384 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 196608, input: 196601, output: 24576 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3-max-2026-01-23": { - id: "qwen3-max-2026-01-23", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-23", - last_updated: "2026-01-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-03", - last_updated: "2026-02-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - }, - }, - venice: { - id: "venice", - env: ["VENICE_API_KEY"], - npm: "venice-ai-sdk-provider", - name: "Venice AI", - doc: "https://docs.venice.ai", - models: { - "openai-gpt-4o-mini-2024-07-18": { - id: "openai-gpt-4o-mini-2024-07-18", - name: "GPT-4o Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-28", - last_updated: "2026-03-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1875, output: 0.75, cache_read: 0.09375 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-next-80b": { - id: "qwen3-next-80b", - name: "Qwen 3 Next 80b", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-04-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.9 }, - limit: { context: 256000, output: 16384 }, - }, - "grok-4-20-multi-agent": { - id: "grok-4-20-multi-agent", - name: "Grok 4.20 Multi-Agent", - family: "grok", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2026-03-12", - last_updated: "2026-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.42, - output: 2.83, - cache_read: 0.23, - context_over_200k: { input: 2.83, output: 5.67, cache_read: 0.45 }, - }, - limit: { context: 2000000, output: 128000 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "Qwen 3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-04-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.75 }, - limit: { context: 128000, output: 16384 }, - }, - "z-ai-glm-5v-turbo": { - id: "z-ai-glm-5v-turbo", - name: "GLM 5V Turbo", - family: "glmv", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 5, cache_read: 0.3 }, - limit: { context: 200000, output: 32768 }, - }, - "gemma-4-uncensored": { - id: "gemma-4-uncensored", - name: "Gemma 4 Uncensored", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-13", - last_updated: "2026-04-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1625, output: 0.5 }, - limit: { context: 256000, output: 8192 }, - }, - "grok-41-fast": { - id: "grok-41-fast", - name: "Grok 4.1 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-12-01", - last_updated: "2026-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.23, output: 0.57, cache_read: 0.06 }, - limit: { context: 1000000, output: 30000 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.6, output: 18, cache_read: 0.36, cache_write: 4.5 }, - limit: { context: 1000000, output: 64000 }, - }, - "nvidia-nemotron-cascade-2-30b-a3b": { - id: "nvidia-nemotron-cascade-2-30b-a3b", - name: "Nemotron Cascade 2 30B A3B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-24", - last_updated: "2026-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.8 }, - limit: { context: 256000, output: 32768 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-19", - last_updated: "2026-03-12", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7, output: 3.75, cache_read: 0.07 }, - limit: { context: 256000, output: 65536 }, - }, - "grok-4-20": { - id: "grok-4-20", - name: "Grok 4.20", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-12", - last_updated: "2026-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.42, - output: 2.83, - cache_read: 0.23, - context_over_200k: { input: 2.83, output: 5.67, cache_read: 0.45 }, - }, - limit: { context: 2000000, output: 128000 }, - }, - "google-gemma-4-26b-a4b-it": { - id: "google-gemma-4-26b-a4b-it", - name: "Google Gemma 4 26B A4B Instruct", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-12", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1625, output: 0.5 }, - limit: { context: 256000, output: 8192 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 6, output: 30, cache_read: 0.6, cache_write: 7.5 }, - limit: { context: 1000000, output: 128000 }, - }, - "qwen3-coder-480b-a35b-instruct-turbo": { - id: "qwen3-coder-480b-a35b-instruct-turbo", - name: "Qwen 3 Coder 480B Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-02-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.5, cache_read: 0.04 }, - limit: { context: 256000, output: 65536 }, - }, - "qwen3-5-397b-a17b": { - id: "qwen3-5-397b-a17b", - name: "Qwen 3.5 397B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 4.5 }, - limit: { context: 128000, output: 32768 }, - }, - "zai-org-glm-4.7": { - id: "zai-org-glm-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-24", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.65, cache_read: 0.11 }, - limit: { context: 198000, output: 16384 }, - }, - "openai-gpt-54": { - id: "openai-gpt-54", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-05", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.13, output: 18.8, cache_read: 0.313 }, - limit: { context: 1000000, output: 131072 }, - }, - "zai-org-glm-4.7-flash": { - id: "zai-org-glm-4.7-flash", - name: "GLM 4.7 Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 128000, output: 16384 }, - }, - "nvidia-nemotron-3-nano-30b-a3b": { - id: "nvidia-nemotron-3-nano-30b-a3b", - name: "NVIDIA Nemotron 3 Nano 30B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-vl-235b-a22b": { - id: "qwen3-vl-235b-a22b", - name: "Qwen3 VL 235B", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-16", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1.5 }, - limit: { context: 256000, output: 16384 }, - }, - "openai-gpt-53-codex": { - id: "openai-gpt-53-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.19, output: 17.5, cache_read: 0.219 }, - limit: { context: 400000, output: 128000 }, - }, - "venice-uncensored-1-2": { - id: "venice-uncensored-1-2", - name: "Venice Uncensored 1.2", - family: "venice", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.9 }, - limit: { context: 128000, output: 8192 }, - }, - "openai-gpt-52": { - id: "openai-gpt-52", - name: "GPT-5.2", - family: "gpt", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2025-12-13", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.19, output: 17.5, cache_read: 0.219 }, - limit: { context: 256000, output: 65536 }, - }, - "mistral-small-3-2-24b-instruct": { - id: "mistral-small-3-2-24b-instruct", - name: "Mistral Small 3.2 24B Instruct", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-15", - last_updated: "2026-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09375, output: 0.25 }, - limit: { context: 256000, output: 16384 }, - }, - "minimax-m27": { - id: "minimax-m27", - name: "MiniMax M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.375, output: 1.5, cache_read: 0.075 }, - limit: { context: 198000, output: 32768 }, - }, - "qwen3-235b-a22b-thinking-2507": { - id: "qwen3-235b-a22b-thinking-2507", - name: "Qwen 3 235B A22B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-04-29", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 3.5 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-5-35b-a3b": { - id: "qwen3-5-35b-a3b", - name: "Qwen 3.5 35B A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-25", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3125, output: 1.25, cache_read: 0.15625 }, - limit: { context: 256000, output: 65536 }, - }, - "mercury-2": { - id: "mercury-2", - name: "Mercury 2", - family: "mercury", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-20", - last_updated: "2026-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3125, output: 0.9375, cache_read: 0.03125 }, - limit: { context: 128000, output: 50000 }, - }, - "google-gemma-3-27b-it": { - id: "google-gemma-3-27b-it", - name: "Google Gemma 3 27B Instruct", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-04", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.2 }, - limit: { context: 198000, output: 16384 }, - }, - "olafangensan-glm-4.7-flash-heretic": { - id: "olafangensan-glm-4.7-flash-heretic", - name: "GLM 4.7 Flash Heretic", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-04", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.8 }, - limit: { context: 200000, output: 24000 }, - }, - "openai-gpt-55-pro": { - id: "openai-gpt-55-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 37.5, output: 225 }, - limit: { context: 1000000, output: 128000 }, - }, - "openai-gpt-52-codex": { - id: "openai-gpt-52-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-01-15", - last_updated: "2026-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.19, output: 17.5, cache_read: 0.219 }, - limit: { context: 256000, output: 65536 }, - }, - "venice-uncensored-role-play": { - id: "venice-uncensored-role-play", - name: "Venice Role Play Uncensored", - family: "venice", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-20", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2 }, - limit: { context: 128000, output: 4096 }, - }, - "zai-org-glm-5": { - id: "zai-org-glm-5", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 198000, output: 32000 }, - }, - "zai-org-glm-4.6": { - id: "zai-org-glm-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2024-04-01", - last_updated: "2026-04-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.85, output: 2.75, cache_read: 0.3 }, - limit: { context: 198000, output: 16384 }, - }, - "grok-4-3": { - id: "grok-4-3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-18", - last_updated: "2026-05-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.42, - output: 2.83, - cache_read: 0.23, - context_over_200k: { input: 2.83, output: 5.67, cache_read: 0.45 }, - }, - limit: { context: 1000000, output: 32000 }, - }, - "mistral-small-2603": { - id: "mistral-small-2603", - name: "Mistral Small 4", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-16", - last_updated: "2026-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1875, output: 0.75 }, - limit: { context: 256000, output: 65536 }, - }, - "openai-gpt-oss-120b": { - id: "openai-gpt-oss-120b", - name: "OpenAI GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-06", - last_updated: "2026-05-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-06", - last_updated: "2026-04-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 6, output: 30, cache_read: 0.6, cache_write: 7.5 }, - limit: { context: 198000, output: 32768 }, - }, - "qwen3-5-9b": { - id: "qwen3-5-9b", - name: "Qwen 3.5 9B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-05", - last_updated: "2026-04-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.15 }, - limit: { context: 256000, output: 32768 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.35, cache_read: 0.028 }, - limit: { context: 1000000, output: 32768 }, - }, - "openai-gpt-54-pro": { - id: "openai-gpt-54-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-05", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 37.5, output: 225, context_over_200k: { input: 75, output: 337.5 } }, - limit: { context: 1000000, output: 128000 }, - }, - "openai-gpt-54-mini": { - id: "openai-gpt-54-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9375, output: 5.625, cache_read: 0.09375 }, - limit: { context: 400000, output: 128000 }, - }, - "minimax-m25": { - id: "minimax-m25", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.34, output: 1.19, cache_read: 0.04 }, - limit: { context: 198000, output: 32768 }, - }, - "zai-org-glm-5-1": { - id: "zai-org-glm-5-1", - name: "GLM 5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.75, output: 5.5, cache_read: 0.325 }, - limit: { context: 200000, output: 24000 }, - }, - "openai-gpt-55": { - id: "openai-gpt-55", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-23", - last_updated: "2026-04-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 6.25, - output: 37.5, - cache_read: 0.625, - context_over_200k: { input: 12.5, output: 56.25, cache_read: 1.25 }, - }, - limit: { context: 1000000, output: 131072 }, - }, - "qwen3-6-27b": { - id: "qwen3-6-27b", - name: "Qwen 3.6 27B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-29", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.325, output: 3.25 }, - limit: { context: 256000, output: 65536 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 6, output: 30, cache_read: 0.6, cache_write: 7.5 }, - limit: { context: 1000000, output: 128000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.73, output: 3.796, cache_read: 0.33 }, - limit: { context: 1000000, output: 32768 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-10", - release_date: "2025-12-04", - last_updated: "2026-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.33, output: 0.48, cache_read: 0.16 }, - limit: { context: 160000, output: 32768 }, - }, - "qwen-3-6-plus": { - id: "qwen-3-6-plus", - name: "Qwen 3.6 Plus Uncensored", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-06", - last_updated: "2026-04-12", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.625, - output: 3.75, - cache_read: 0.0625, - cache_write: 0.78, - context_over_200k: { input: 2.5, output: 7.5, cache_read: 0.0625, cache_write: 0.78 }, - }, - limit: { context: 1000000, output: 65536 }, - }, - "aion-labs-aion-2-0": { - id: "aion-labs-aion-2-0", - name: "Aion 2.0", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-24", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2, cache_read: 0.25 }, - limit: { context: 128000, output: 32768 }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-15", - last_updated: "2026-04-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.75, output: 18.75, cache_read: 0.375, cache_write: 4.69 }, - limit: { context: 198000, output: 64000 }, - }, - "openai-gpt-4o-2024-11-20": { - id: "openai-gpt-4o-2024-11-20", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-28", - last_updated: "2026-03-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3.125, output: 12.5 }, - limit: { context: 128000, output: 16384 }, - }, - "llama-3.3-70b": { - id: "llama-3.3-70b", - name: "Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-04-06", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8 }, - limit: { context: 128000, output: 4096 }, - }, - "kimi-k2-5": { - id: "kimi-k2-5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-01-27", - last_updated: "2026-04-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 3.5, cache_read: 0.22 }, - limit: { context: 256000, output: 65536 }, - }, - "llama-3.2-3b": { - id: "llama-3.2-3b", - name: "Llama 3.2 3B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-10-03", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "arcee-trinity-large-thinking": { - id: "arcee-trinity-large-thinking", - name: "Trinity Large Thinking", - family: "trinity", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3125, output: 1.125, cache_read: 0.075 }, - limit: { context: 256000, output: 65536 }, - }, - "hermes-3-llama-3.1-405b": { - id: "hermes-3-llama-3.1-405b", - name: "Hermes 3 Llama 3.1 405b", - family: "hermes", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-04", - release_date: "2025-09-25", - last_updated: "2026-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.1, output: 3 }, - limit: { context: 128000, output: 16384 }, - }, - "gemini-3-1-pro-preview": { - id: "gemini-3-1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-19", - last_updated: "2026-03-12", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.5, - cache_write: 0.5, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1000000, output: 32768 }, - }, - "kimi-k2-6": { - id: "kimi-k2-6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.85, output: 4.655, cache_read: 0.22 }, - limit: { context: 256000, output: 65536 }, - }, - "claude-opus-4-6-fast": { - id: "claude-opus-4-6-fast", - name: "Claude Opus 4.6 Fast", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 36, output: 180, cache_read: 3.6, cache_write: 45 }, - limit: { context: 1000000, output: 128000 }, - }, - "z-ai-glm-5-turbo": { - id: "z-ai-glm-5-turbo", - name: "GLM 5 Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 4, cache_read: 0.24 }, - limit: { context: 200000, output: 32768 }, - }, - "google-gemma-4-31b-it": { - id: "google-gemma-4-31b-it", - name: "Google Gemma 4 31B Instruct", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-03", - last_updated: "2026-04-12", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.175, output: 0.5 }, - limit: { context: 256000, output: 8192 }, - }, - }, - }, - aihubmix: { - id: "aihubmix", - env: ["AIHUBMIX_API_KEY"], - npm: "@aihubmix/ai-sdk-provider", - name: "AIHubMix", - doc: "https://docs.aihubmix.com", - models: { - "minimax-m2.7": { - id: "minimax-m2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2958, output: 1.1832, cache_read: 0.05916 }, - limit: { context: 200000, output: 128000 }, - }, - "coding-glm-5.1-free": { - id: "coding-glm-5.1-free", - name: "Coding GLM 5.1 (free)", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-11", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 204800, output: 128000 }, - }, - "gemini-3.1-pro-preview-customtools": { - id: "gemini-3.1-pro-preview-customtools", - name: "Gemini 3.1 Pro Preview Custom Tools", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-k2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.105 }, - limit: { context: 256000, output: 0 }, - }, - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM 5 Vision Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-05-09", - last_updated: "2026-05-09", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.7042, output: 3.09848, cache_read: 0.169008 }, - limit: { context: 200000, output: 128000 }, - }, - "grok-4.3": { - id: "grok-4.3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-05-01", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 2.5, - cache_read: 0.2, - context_over_200k: { input: 2.5, output: 5, cache_read: 0.4 }, - }, - limit: { context: 1000000, output: 1000000 }, - }, - "coding-minimax-m2.7-highspeed": { - id: "coding-minimax-m2.7-highspeed", - name: "Coding MiniMax M2.7 Highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 204800, output: 13100 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 1048576, output: 65536 }, - }, - "coding-glm-5.1": { - id: "coding-glm-5.1", - name: "Coding-GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-11", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.22 }, - limit: { context: 200000, output: 128000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 1050000, output: 128000 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "deepseek-v4-flash-think": { - id: "deepseek-v4-flash-think", - name: "DeepSeek V4 Flash Think", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.154, output: 0.308, cache_read: 0.0308 }, - limit: { context: 1000000, output: 384000 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-05-09", - last_updated: "2026-05-09", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.282, output: 1.692, cache_read: 0.0282, cache_write: 0.3525 }, - limit: { context: 991000, output: 64000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4-Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: false, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.845, output: 3.38, cache_read: 0.183112 }, - limit: { context: 200000, output: 128000 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.275 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.499, cache_read: 0.03 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-3.1-flash-lite": { - id: "gemini-3.1-flash-lite", - name: "Gemini 3.1 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.25 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-15", - last_updated: "2025-11-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-6-think": { - id: "claude-opus-4-6-think", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 32000 }, - }, - "coding-minimax-m2.7-free": { - id: "coding-minimax-m2.7-free", - name: "Coding-MiniMax-M2.7-Free", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 13100 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.154, output: 0.308, cache_read: 0.0308 }, - limit: { context: 1000000, output: 384000 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 3.9995, cache_read: 0.160835 }, - limit: { context: 262144, output: 262144 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.478, output: 0.956, cache_read: 0.004302 }, - limit: { context: 1000000, output: 384000 }, - }, - "claude-opus-4-7-think": { - id: "claude-opus-4-7-think", - name: "Claude Opus 4.7 Thinking", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 32000 }, - }, - "coding-minimax-m2.7": { - id: "coding-minimax-m2.7", - name: "Coding MiniMax M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 204800, output: 13100 }, - }, - "qwen3.6-max-preview": { - id: "qwen3.6-max-preview", - name: "Qwen3.6 Max Preview", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-05-09", - last_updated: "2026-05-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.268, output: 7.608, cache_read: 0.1268, cache_write: 1.585 }, - limit: { context: 240000, output: 64000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-sonnet-4-6-think": { - id: "claude-sonnet-4-6-think", - name: "Claude Sonnet 4.6 Think", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 200000, output: 64000 }, - }, - "qwen3.6-flash": { - id: "qwen3.6-flash", - name: "Qwen3.6 Flash", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.169, output: 1.014, cache_read: 0.0169, cache_write: 0.21125 }, - limit: { context: 991000, output: 64000 }, - }, - }, - }, - cerebras: { - id: "cerebras", - env: ["CEREBRAS_API_KEY"], - npm: "@ai-sdk/cerebras", - name: "Cerebras", - doc: "https://inference-docs.cerebras.ai/models/overview", - models: { - "llama3.1-8b": { - id: "llama3.1-8b", - name: "Llama 3.1 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 32000, output: 8000 }, - }, - "qwen-3-235b-a22b-instruct-2507": { - id: "qwen-3-235b-a22b-instruct-2507", - name: "Qwen 3 235B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-22", - last_updated: "2025-07-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.2 }, - limit: { context: 131000, output: 32000 }, - }, - "zai-glm-4.7": { - id: "zai-glm-4.7", - name: "Z.AI GLM-4.7", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-01-10", - last_updated: "2026-01-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.25, output: 2.75, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 40000 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.69 }, - limit: { context: 131072, output: 32768 }, - }, - }, - }, - lmstudio: { - id: "lmstudio", - env: ["LMSTUDIO_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "http://127.0.0.1:1234/v1", - name: "LMStudio", - doc: "https://lmstudio.ai/models", - models: { - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 32768 }, - }, - "qwen/qwen3-coder-30b": { - id: "qwen/qwen3-coder-30b", - name: "Qwen3 Coder 30B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwen3-30b-a3b-2507": { - id: "qwen/qwen3-30b-a3b-2507", - name: "Qwen3 30B A3B 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 16384 }, - }, - }, - }, - lucidquery: { - id: "lucidquery", - env: ["LUCIDQUERY_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://lucidquery.com/api/v1", - name: "LucidQuery AI", - doc: "https://lucidquery.com/api/docs", - models: { - "lucidnova-rf1-100b": { - id: "lucidnova-rf1-100b", - name: "LucidNova RF1 100B", - family: "nova", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-09-16", - release_date: "2024-12-28", - last_updated: "2025-09-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 5 }, - limit: { context: 120000, output: 8000 }, - }, - "lucidquery-nexus-coder": { - id: "lucidquery-nexus-coder", - name: "LucidQuery Nexus Coder", - family: "lucid", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-01", - release_date: "2025-09-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 5 }, - limit: { context: 250000, output: 60000 }, - }, - }, - }, - "moonshotai-cn": { - id: "moonshotai-cn", - env: ["MOONSHOT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.moonshot.cn/v1", - name: "Moonshot AI (China)", - doc: "https://platform.moonshot.cn/docs/api/chat", - models: { - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-0711-preview": { - id: "kimi-k2-0711-preview", - name: "Kimi K2 0711", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-14", - last_updated: "2025-07-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 131072, output: 16384 }, - }, - "kimi-k2-turbo-preview": { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.4, output: 10, cache_read: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.15, output: 8, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-k2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-0905-preview": { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - "azure-cognitive-services": { - id: "azure-cognitive-services", - env: ["AZURE_COGNITIVE_SERVICES_RESOURCE_NAME", "AZURE_COGNITIVE_SERVICES_API_KEY"], - npm: "@ai-sdk/azure", - name: "Azure Cognitive Services", - doc: "https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models", - models: { - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "claude-opus-4-1": { - id: "claude-opus-4-1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4 }, - limit: { context: 262144, output: 262144 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", - shape: "completions", - }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 200000, output: 128000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_COGNITIVE_SERVICES_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "mai-ds-r1": { - id: "mai-ds-r1", - name: "MAI-DS-R1", - family: "mai", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 128000, output: 8192 }, - }, - "llama-4-maverick-17b-128e-instruct-fp8": { - id: "llama-4-maverick-17b-128e-instruct-fp8", - name: "Llama 4 Maverick 17B 128E Instruct FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1 }, - limit: { context: 128000, output: 8192 }, - }, - "codestral-2501": { - id: "codestral-2501", - name: "Codestral 25.01", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 256000 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek-R1-0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 163840, output: 163840 }, - }, - "gpt-3.5-turbo-instruct": { - id: "gpt-3.5-turbo-instruct", - name: "GPT-3.5 Turbo Instruct", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-09-21", - last_updated: "2023-09-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 4096, output: 4096 }, - }, - "mistral-medium-2505": { - id: "mistral-medium-2505", - name: "Mistral Medium 3", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 128000, output: 128000 }, - }, - "phi-4-reasoning-plus": { - id: "phi-4-reasoning-plus", - name: "Phi-4-reasoning-plus", - family: "phi", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 32000, output: 4096 }, - }, - "cohere-embed-v3-english": { - id: "cohere-embed-v3-english", - name: "Embed v3 English", - family: "cohere-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-11-07", - last_updated: "2023-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0 }, - limit: { context: 512, output: 1024 }, - }, - "gpt-4-32k": { - id: "gpt-4-32k", - name: "GPT-4 32K", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-03-14", - last_updated: "2023-03-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 60, output: 120 }, - limit: { context: 32768, output: 32768 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 272000, output: 128000 }, - }, - "phi-4": { - id: "phi-4", - name: "Phi-4", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-3.5-turbo-0613": { - id: "gpt-3.5-turbo-0613", - name: "GPT-3.5 Turbo 0613", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-06-13", - last_updated: "2023-06-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 4 }, - limit: { context: 16384, output: 16384 }, - }, - "phi-3-medium-128k-instruct": { - id: "phi-3-medium-128k-instruct", - name: "Phi-3-medium-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 1.68 }, - limit: { context: 128000, output: 128000 }, - }, - "phi-3-small-128k-instruct": { - id: "phi-3-small-128k-instruct", - name: "Phi-3-small-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-3.5-turbo-0301": { - id: "gpt-3.5-turbo-0301", - name: "GPT-3.5 Turbo 0301", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-03-01", - last_updated: "2023-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 4096, output: 4096 }, - }, - "phi-4-mini": { - id: "phi-4-mini", - name: "Phi-4-mini", - family: "phi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "GPT-5-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, output: 128000 }, - }, - "meta-llama-3-8b-instruct": { - id: "meta-llama-3-8b-instruct", - name: "Meta-Llama-3-8B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.61 }, - limit: { context: 8192, output: 2048 }, - }, - "gpt-4": { - id: "gpt-4", - name: "GPT-4", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-03-14", - last_updated: "2023-03-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 60, output: 120 }, - limit: { context: 8192, output: 8192 }, - }, - "phi-4-mini-reasoning": { - id: "phi-4-mini-reasoning", - name: "Phi-4-mini-reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, output: 4096 }, - }, - "meta-llama-3.1-70b-instruct": { - id: "meta-llama-3.1-70b-instruct", - name: "Meta-Llama-3.1-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.68, output: 3.54 }, - limit: { context: 128000, output: 32768 }, - }, - "phi-3-mini-4k-instruct": { - id: "phi-3-mini-4k-instruct", - name: "Phi-3-mini-instruct (4k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 4096, output: 1024 }, - }, - "deepseek-v3.1": { - id: "deepseek-v3.1", - name: "DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68 }, - limit: { context: 131072, output: 131072 }, - }, - "text-embedding-3-small": { - id: "text-embedding-3-small", - name: "text-embedding-3-small", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8191, output: 1536 }, - }, - "gpt-3.5-turbo-1106": { - id: "gpt-3.5-turbo-1106", - name: "GPT-3.5 Turbo 1106", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-11-06", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2 }, - limit: { context: 16384, output: 16384 }, - }, - "model-router": { - id: "model-router", - name: "Model Router", - family: "model-router", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2025-05-19", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "mistral-small-2503": { - id: "mistral-small-2503", - name: "Mistral Small 3.1", - family: "mistral-small", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 32768 }, - }, - o1: { - id: "o1", - name: "o1", - family: "o", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "Grok 4 Fast (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 272000, output: 128000 }, - }, - "cohere-embed-v3-multilingual": { - id: "cohere-embed-v3-multilingual", - name: "Embed v3 Multilingual", - family: "cohere-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-11-07", - last_updated: "2023-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0 }, - limit: { context: 512, output: 1024 }, - }, - "o1-preview": { - id: "o1-preview", - name: "o1-preview", - family: "o", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 16.5, output: 66, cache_read: 8.25 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-3.5-turbo-0125": { - id: "gpt-3.5-turbo-0125", - name: "GPT-3.5 Turbo 0125", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 16384, output: 16384 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex Mini", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "cohere-embed-v-4-0": { - id: "cohere-embed-v-4-0", - name: "Embed v4", - family: "cohere-embed", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0 }, - limit: { context: 128000, output: 1536 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-4-turbo-vision": { - id: "gpt-4-turbo-vision", - name: "GPT-4 Turbo Vision", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5.1-chat": { - id: "gpt-5.1-chat", - name: "GPT-5.1 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "meta-llama-3.1-405b-instruct": { - id: "meta-llama-3.1-405b-instruct", - name: "Meta-Llama-3.1-405B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 5.33, output: 16 }, - limit: { context: 128000, output: 32768 }, - }, - "llama-3.2-11b-vision-instruct": { - id: "llama-3.2-11b-vision-instruct", - name: "Llama-3.2-11B-Vision-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.37, output: 0.37 }, - limit: { context: 128000, output: 8192 }, - }, - "cohere-command-a": { - id: "cohere-command-a", - name: "Command A", - family: "command-a", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 8000 }, - }, - "mistral-large-2411": { - id: "mistral-large-2411", - name: "Mistral Large 24.11", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "deepseek-v3.2-speciale": { - id: "deepseek-v3.2-speciale", - name: "DeepSeek-V3.2-Speciale", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 1.68 }, - limit: { context: 128000, output: 128000 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 163840, output: 163840 }, - }, - "llama-3.2-90b-vision-instruct": { - id: "llama-3.2-90b-vision-instruct", - name: "Llama-3.2-90B-Vision-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.04, output: 2.04 }, - limit: { context: 128000, output: 8192 }, - }, - "text-embedding-ada-002": { - id: "text-embedding-ada-002", - name: "text-embedding-ada-002", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2022-12-15", - last_updated: "2022-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "phi-3-small-8k-instruct": { - id: "phi-3-small-8k-instruct", - name: "Phi-3-small-instruct (8k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 8192, output: 2048 }, - }, - "meta-llama-3-70b-instruct": { - id: "meta-llama-3-70b-instruct", - name: "Meta-Llama-3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.68, output: 3.54 }, - limit: { context: 8192, output: 2048 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.01 }, - limit: { context: 272000, output: 128000 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 272000, output: 128000 }, - }, - "phi-4-reasoning": { - id: "phi-4-reasoning", - name: "Phi-4-reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 32000, output: 4096 }, - }, - "phi-3-mini-128k-instruct": { - id: "phi-3-mini-128k-instruct", - name: "Phi-3-mini-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 128000, output: 4096 }, - }, - "text-embedding-3-large": { - id: "text-embedding-3-large", - name: "text-embedding-3-large", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0 }, - limit: { context: 8191, output: 3072 }, - }, - "o1-mini": { - id: "o1-mini", - name: "o1-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 128000, output: 65536 }, - }, - "phi-3.5-moe-instruct": { - id: "phi-3.5-moe-instruct", - name: "Phi-3.5-MoE-instruct", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.16, output: 0.64 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5-chat": { - id: "gpt-5-chat", - name: "GPT-5 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2024-10-24", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 128000, output: 16384 }, - }, - "deepseek-v3-0324": { - id: "deepseek-v3-0324", - name: "DeepSeek-V3-0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.14, output: 4.56 }, - limit: { context: 131072, output: 131072 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.71, output: 0.71 }, - limit: { context: 128000, output: 32768 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 262144 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", - shape: "completions", - }, - }, - "meta-llama-3.1-8b-instruct": { - id: "meta-llama-3.1-8b-instruct", - name: "Meta-Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.61 }, - limit: { context: 128000, output: 32768 }, - }, - "ministral-3b": { - id: "ministral-3b", - name: "Ministral 3B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 128000, output: 8192 }, - }, - "phi-3-medium-4k-instruct": { - id: "phi-3-medium-4k-instruct", - name: "Phi-3-medium-instruct (4k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 4096, output: 1024 }, - }, - "llama-4-scout-17b-16e-instruct": { - id: "llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.78 }, - limit: { context: 128000, output: 8192 }, - }, - "phi-3.5-mini-instruct": { - id: "phi-3.5-mini-instruct", - name: "Phi-3.5-mini-instruct", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 128000, output: 4096 }, - }, - "phi-4-multimodal": { - id: "phi-4-multimodal", - name: "Phi-4-multimodal", - family: "phi", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.32, input_audio: 4 }, - limit: { context: 128000, output: 4096 }, - }, - "codex-mini": { - id: "codex-mini", - name: "Codex Mini", - family: "gpt-codex-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-04", - release_date: "2025-05-16", - last_updated: "2025-05-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 6, cache_read: 0.375 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.2-chat": { - id: "gpt-5.2-chat", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "mistral-nemo": { - id: "mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 128000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-3": { - id: "grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "cohere-command-r-plus-08-2024": { - id: "cohere-command-r-plus-08-2024", - name: "Command R+", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 4000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, output: 272000 }, - }, - o3: { - id: "o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "grok-3-mini": { - id: "grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, reasoning: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "GPT-4.1 nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03 }, - limit: { context: 1047576, output: 32768 }, - }, - "grok-4": { - id: "grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, reasoning: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "cohere-command-r-08-2024": { - id: "cohere-command-r-08-2024", - name: "Command R", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4000 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-4-turbo": { - id: "gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - }, - }, - "abliteration-ai": { - id: "abliteration-ai", - env: ["ABLIT_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.abliteration.ai/v1", - name: "abliteration.ai", - doc: "https://docs.abliteration.ai/models", - models: { - "abliterated-model": { - id: "abliterated-model", - name: "Abliterated Model", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-01-06", - last_updated: "2026-01-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 3 }, - limit: { context: 150000, input: 150000, output: 8192 }, - }, - }, - }, - "wafer.ai": { - id: "wafer.ai", - env: ["WAFER_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://pass.wafer.ai/v1", - name: "Wafer", - doc: "https://docs.wafer.ai/wafer-pass", - models: { - "Qwen3.5-397B-A17B": { - id: "Qwen3.5-397B-A17B", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "GLM-5.1": { - id: "GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 131072 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "DeepSeek-V4-Pro": { - id: "DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 384000 }, - }, - }, - }, - cohere: { - id: "cohere", - env: ["COHERE_API_KEY"], - npm: "@ai-sdk/cohere", - name: "Cohere", - doc: "https://docs.cohere.com/docs/models", - models: { - "command-a-reasoning-08-2025": { - id: "command-a-reasoning-08-2025", - name: "Command A Reasoning", - family: "command-a", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 32000 }, - }, - "command-r7b-12-2024": { - id: "command-r7b-12-2024", - name: "Command R7B", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-02-27", - last_updated: "2024-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0375, output: 0.15 }, - limit: { context: 128000, output: 4000 }, - }, - "c4ai-aya-vision-8b": { - id: "c4ai-aya-vision-8b", - name: "Aya Vision 8B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-04", - last_updated: "2025-05-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 16000, output: 4000 }, - }, - "command-r-plus-08-2024": { - id: "command-r-plus-08-2024", - name: "Command R+", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 4000 }, - }, - "c4ai-aya-expanse-8b": { - id: "c4ai-aya-expanse-8b", - name: "Aya Expanse 8B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-10-24", - last_updated: "2024-10-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 8000, output: 4000 }, - }, - "command-r7b-arabic-02-2025": { - id: "command-r7b-arabic-02-2025", - name: "Command R7B Arabic", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-02-27", - last_updated: "2025-02-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.0375, output: 0.15 }, - limit: { context: 128000, output: 4000 }, - }, - "command-a-vision-07-2025": { - id: "command-a-vision-07-2025", - name: "Command A Vision", - family: "command-a", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 8000 }, - }, - "c4ai-aya-vision-32b": { - id: "c4ai-aya-vision-32b", - name: "Aya Vision 32B", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-03-04", - last_updated: "2025-05-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 16000, output: 4000 }, - }, - "command-a-translate-08-2025": { - id: "command-a-translate-08-2025", - name: "Command A Translate", - family: "command-a", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 8000, output: 8000 }, - }, - "command-r-08-2024": { - id: "command-r-08-2024", - name: "Command R", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4000 }, - }, - "c4ai-aya-expanse-32b": { - id: "c4ai-aya-expanse-32b", - name: "Aya Expanse 32B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-10-24", - last_updated: "2024-10-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 128000, output: 4000 }, - }, - "command-a-03-2025": { - id: "command-a-03-2025", - name: "Command A", - family: "command-a", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 8000 }, - }, - }, - }, - "cloudferro-sherlock": { - id: "cloudferro-sherlock", - env: ["CLOUDFERRO_SHERLOCK_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api-sherlock.cloudferro.com/openai/v1/", - name: "CloudFerro Sherlock", - doc: "https://docs.sherlock.cloudferro.com/", - models: { - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10-09", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.92, output: 2.92 }, - limit: { context: 70000, output: 70000 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "OpenAI GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.92, output: 2.92 }, - limit: { context: 131000, output: 131000 }, - }, - "speakleash/Bielik-11B-v3.0-Instruct": { - id: "speakleash/Bielik-11B-v3.0-Instruct", - name: "Bielik 11B v3.0 Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.67, output: 0.67 }, - limit: { context: 32000, output: 32000 }, - }, - "speakleash/Bielik-11B-v2.6-Instruct": { - id: "speakleash/Bielik-11B-v2.6-Instruct", - name: "Bielik 11B v2.6 Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.67, output: 0.67 }, - limit: { context: 32000, output: 32000 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196000, input: 180000, output: 16000 }, - }, - }, - }, - "kuae-cloud-coding-plan": { - id: "kuae-cloud-coding-plan", - env: ["KUAE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://coding-plan-endpoint.kuaecloud.net/v1", - name: "KUAE Cloud Coding Plan", - doc: "https://docs.mthreads.com/kuaecloud/kuaecloud-doc-online/coding_plan/", - models: { - "GLM-4.7": { - id: "GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - xai: { - id: "xai", - env: ["XAI_API_KEY"], - npm: "@ai-sdk/xai", - name: "xAI", - doc: "https://docs.x.ai/docs/models", - models: { - "grok-2-1212": { - id: "grok-2-1212", - name: "Grok 2 (1212)", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-12-12", - last_updated: "2024-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-vision-beta": { - id: "grok-vision-beta", - name: "Grok Vision Beta", - family: "grok-vision", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 15, cache_read: 5 }, - limit: { context: 8192, output: 4096 }, - }, - "grok-4.3": { - id: "grok-4.3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-05-01", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 2.5, - cache_read: 0.2, - context_over_200k: { input: 2.5, output: 5, cache_read: 0.4 }, - }, - limit: { context: 1000000, output: 30000 }, - }, - "grok-3-mini-fast": { - id: "grok-3-mini-fast", - name: "Grok 3 Mini Fast", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4, reasoning: 4, cache_read: 0.15 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-3-mini-latest": { - id: "grok-3-mini-latest", - name: "Grok 3 Mini Latest", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, reasoning: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-3-fast": { - id: "grok-3-fast", - name: "Grok 3 Fast", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 1.25 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-2-vision-latest": { - id: "grok-2-vision-latest", - name: "Grok 2 Vision Latest", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-12-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 8192, output: 4096 }, - }, - "grok-4.20-0309-reasoning": { - id: "grok-4.20-0309-reasoning", - name: "Grok 4.20 (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12, cache_read: 0.4 } }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-3-mini-fast-latest": { - id: "grok-3-mini-fast-latest", - name: "Grok 3 Mini Fast Latest", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4, reasoning: 4, cache_read: 0.15 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4-fast": { - id: "grok-4-fast", - name: "Grok 4 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-3-latest": { - id: "grok-3-latest", - name: "Grok 3 Latest", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-2": { - id: "grok-2", - name: "Grok 2", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "grok-4.20-0309-non-reasoning": { - id: "grok-4.20-0309-non-reasoning", - name: "Grok 4.20 (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12, cache_read: 0.4 } }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-3-fast-latest": { - id: "grok-3-fast-latest", - name: "Grok 3 Fast Latest", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 1.25 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4.20-multi-agent-0309": { - id: "grok-4.20-multi-agent-0309", - name: "Grok 4.20 Multi-Agent", - family: "grok", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12, cache_read: 0.4 } }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-4": { - id: "grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, reasoning: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "grok-2-latest": { - id: "grok-2-latest", - name: "Grok 2 Latest", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-beta": { - id: "grok-beta", - name: "Grok Beta", - family: "grok-beta", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 15, cache_read: 5 }, - limit: { context: 131072, output: 4096 }, - }, - "grok-2-vision": { - id: "grok-2-vision", - name: "Grok 2 Vision", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 8192, output: 4096 }, - }, - "grok-4-1-fast": { - id: "grok-4-1-fast", - name: "Grok 4.1 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "grok-3-mini": { - id: "grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, reasoning: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-2-vision-1212": { - id: "grok-2-vision-1212", - name: "Grok 2 Vision (1212)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-12-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 8192, output: 4096 }, - }, - "grok-3": { - id: "grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - }, - }, - meganova: { - id: "meganova", - env: ["MEGANOVA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.meganova.ai/v1", - name: "Meganova", - doc: "https://docs.meganova.ai", - models: { - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3.5-Plus": { - id: "Qwen/Qwen3.5-Plus", - name: "Qwen3.5 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02", - last_updated: "2026-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4, reasoning: 2.4 }, - limit: { context: 1000000, output: 65536 }, - }, - "Qwen/Qwen2.5-VL-32B-Instruct": { - id: "Qwen/Qwen2.5-VL-32B-Instruct", - name: "Qwen2.5 VL 32B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 16384, output: 16384 }, - }, - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 202752, output: 131072 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.56 }, - limit: { context: 202752, output: 131072 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 1.9 }, - limit: { context: 202752, output: 131072 }, - }, - "mistralai/Mistral-Small-3.2-24B-Instruct-2506": { - id: "mistralai/Mistral-Small-3.2-24B-Instruct-2506", - name: "Mistral Small 3.2 24B Instruct", - family: "mistral-small", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-06-20", - last_updated: "2025-06-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "mistralai/Mistral-Nemo-Instruct-2407": { - id: "mistralai/Mistral-Nemo-Instruct-2407", - name: "Mistral Nemo Instruct 2407", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.04 }, - limit: { context: 131072, output: 65536 }, - }, - "XiaomiMiMo/MiMo-V2-Flash": { - id: "XiaomiMiMo/MiMo-V2-Flash", - name: "MiMo V2 Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 262144, output: 32000 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 131072, output: 16384 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-25", - last_updated: "2025-08-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-V3-0324": { - id: "deepseek-ai/DeepSeek-V3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.88 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek-ai/DeepSeek-V3.2-Exp": { - id: "deepseek-ai/DeepSeek-V3.2-Exp", - name: "DeepSeek V3.2 Exp", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-10", - last_updated: "2025-10-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.4 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-R1-0528": { - id: "deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.15 }, - limit: { context: 163840, output: 64000 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.26, output: 0.38 }, - limit: { context: 164000, output: 164000 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.6 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2026-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.8 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMaxAI/MiniMax-M2.1": { - id: "MiniMaxAI/MiniMax-M2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.2 }, - limit: { context: 196608, output: 131072 }, - }, - }, - }, - "google-vertex-anthropic": { - id: "google-vertex-anthropic", - env: ["GOOGLE_VERTEX_PROJECT", "GOOGLE_VERTEX_LOCATION", "GOOGLE_APPLICATION_CREDENTIALS"], - npm: "@ai-sdk/google-vertex/anthropic", - name: "Vertex (Anthropic)", - doc: "https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/claude", - models: { - "claude-haiku-4-5@20251001": { - id: "claude-haiku-4-5@20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-sonnet-4-6@default": { - id: "claude-sonnet-4-6@default", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 200000, output: 64000 }, - }, - "claude-3-5-haiku@20241022": { - id: "claude-3-5-haiku@20241022", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-3-5-sonnet@20241022": { - id: "claude-3-5-sonnet@20241022", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-opus-4-1@20250805": { - id: "claude-opus-4-1@20250805", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-sonnet-4@20250514": { - id: "claude-sonnet-4@20250514", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-3-7-sonnet@20250219": { - id: "claude-3-7-sonnet@20250219", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4@20250514": { - id: "claude-opus-4@20250514", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-opus-4-5@20251101": { - id: "claude-opus-4-5@20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-sonnet-4-5@20250929": { - id: "claude-sonnet-4-5@20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-6@default": { - id: "claude-opus-4-6@default", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "claude-opus-4-7@default": { - id: "claude-opus-4-7@default", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - }, - }, - evroc: { - id: "evroc", - env: ["EVROC_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://models.think.evroc.com/v1", - name: "evroc", - doc: "https://docs.evroc.com/products/think/overview.html", - models: { - "Qwen/Qwen3-VL-30B-A3B-Instruct": { - id: "Qwen/Qwen3-VL-30B-A3B-Instruct", - name: "Qwen3 VL 30B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.94 }, - limit: { context: 100000, output: 100000 }, - }, - "Qwen/Qwen3-Embedding-8B": { - id: "Qwen/Qwen3-Embedding-8B", - name: "Qwen3 Embedding 8B", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.12 }, - limit: { context: 40960, output: 40960 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8", - name: "Qwen3 30B 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.42 }, - limit: { context: 64000, output: 64000 }, - }, - "mistralai/devstral-small-2-24b-instruct-2512": { - id: "mistralai/devstral-small-2-24b-instruct-2512", - name: "Devstral Small 2 24B Instruct 2512", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.47 }, - limit: { context: 32768, output: 32768 }, - }, - "mistralai/Voxtral-Small-24B-2507": { - id: "mistralai/Voxtral-Small-24B-2507", - name: "Voxtral Small 24B", - family: "voxtral", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["audio", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.00236, output: 0.00236, output_audio: 2.36 }, - limit: { context: 32000, output: 32000 }, - }, - "mistralai/Magistral-Small-2509": { - id: "mistralai/Magistral-Small-2509", - name: "Magistral Small 1.2 24B", - family: "magistral-small", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-06-01", - last_updated: "2025-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.59, output: 2.36 }, - limit: { context: 131072, output: 131072 }, - }, - "microsoft/Phi-4-multimodal-instruct": { - id: "microsoft/Phi-4-multimodal-instruct", - name: "Phi-4 15B", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.47 }, - limit: { context: 32000, output: 32000 }, - }, - "KBLab/kb-whisper-large": { - id: "KBLab/kb-whisper-large", - name: "KB Whisper", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.00236, output: 0.00236, output_audio: 2.36 }, - limit: { context: 448, output: 448 }, - }, - "nvidia/Llama-3.3-70B-Instruct-FP8": { - id: "nvidia/Llama-3.3-70B-Instruct-FP8", - name: "Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.18, output: 1.18 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/whisper-large-v3": { - id: "openai/whisper-large-v3", - name: "Whisper 3 Large", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.00236, output: 0.00236, output_audio: 2.36 }, - limit: { context: 448, output: 4096 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.94 }, - limit: { context: 65536, output: 65536 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 1.47, output: 5.9 }, - limit: { context: 262144, output: 262144 }, - }, - "intfloat/multilingual-e5-large-instruct": { - id: "intfloat/multilingual-e5-large-instruct", - name: "E5 Multi-Lingual Large Embeddings 0.6B", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-06-01", - last_updated: "2024-06-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.12 }, - limit: { context: 512, output: 512 }, - }, - }, - }, - synthetic: { - id: "synthetic", - env: ["SYNTHETIC_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.synthetic.new/openai/v1", - name: "Synthetic", - doc: "https://synthetic.new/pricing", - models: { - "hf:meta-llama/Llama-3.1-405B-Instruct": { - id: "hf:meta-llama/Llama-3.1-405B-Instruct", - name: "Llama-3.1-405B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 3 }, - limit: { context: 128000, output: 32768 }, - }, - "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct": { - id: "hf:meta-llama/Llama-4-Scout-17B-16E-Instruct", - name: "Llama-4-Scout-17B-16E-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 328000, output: 4096 }, - }, - "hf:meta-llama/Llama-3.3-70B-Instruct": { - id: "hf:meta-llama/Llama-3.3-70B-Instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 0.9 }, - limit: { context: 128000, output: 32768 }, - }, - "hf:meta-llama/Llama-3.1-8B-Instruct": { - id: "hf:meta-llama/Llama-3.1-8B-Instruct", - name: "Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 128000, output: 32768 }, - }, - "hf:meta-llama/Llama-3.1-70B-Instruct": { - id: "hf:meta-llama/Llama-3.1-70B-Instruct", - name: "Llama-3.1-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 0.9 }, - 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", - name: "Llama-4-Maverick-17B-128E-Instruct-FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.88 }, - limit: { context: 524000, output: 4096 }, - }, - "hf:MiniMaxAI/MiniMax-M2": { - id: "hf:MiniMaxAI/MiniMax-M2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 196608, output: 131000 }, - }, - "hf:MiniMaxAI/MiniMax-M2.5": { - id: "hf:MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-07", - last_updated: "2026-02-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.6 }, - limit: { context: 191488, output: 65536 }, - }, - "hf:MiniMaxAI/MiniMax-M2.1": { - id: "hf:MiniMaxAI/MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 204800, output: 131072 }, - }, - "hf:Qwen/Qwen3.5-397B-A17B": { - id: "hf:Qwen/Qwen3.5-397B-A17B", - name: "Qwen3.5-97B-A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.6 }, - limit: { context: 262144, output: 65536 }, - status: "beta", - }, - "hf:Qwen/Qwen2.5-Coder-32B-Instruct": { - id: "hf:Qwen/Qwen2.5-Coder-32B-Instruct", - name: "Qwen2.5-Coder-32B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-11-11", - last_updated: "2024-11-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 0.8 }, - limit: { context: 32768, output: 32768 }, - }, - "hf:Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "hf:Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen 3 235B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-28", - last_updated: "2025-07-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 256000, output: 32000 }, - }, - "hf:Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "hf:Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3 235B A22B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 3 }, - limit: { context: 256000, output: 32000 }, - }, - "hf:Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "hf:Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen 3 Coder 480B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 2 }, - limit: { context: 256000, output: 32000 }, - }, - "hf:deepseek-ai/DeepSeek-V3.1": { - id: "hf:deepseek-ai/DeepSeek-V3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.56, output: 1.68 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:deepseek-ai/DeepSeek-V3-0324": { - id: "hf:deepseek-ai/DeepSeek-V3-0324", - name: "DeepSeek V3 (0324)", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 1.2 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:deepseek-ai/DeepSeek-V3": { - id: "hf:deepseek-ai/DeepSeek-V3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.25, output: 1.25 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:deepseek-ai/DeepSeek-R1": { - id: "hf:deepseek-ai/DeepSeek-R1", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:deepseek-ai/DeepSeek-R1-0528": { - id: "hf:deepseek-ai/DeepSeek-R1-0528", - name: "DeepSeek R1 (0528)", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 8 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:deepseek-ai/DeepSeek-V3.2": { - id: "hf:deepseek-ai/DeepSeek-V3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.4, cache_read: 0.27, cache_write: 0 }, - limit: { context: 162816, input: 162816, output: 8000 }, - }, - "hf:deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "hf:deepseek-ai/DeepSeek-V3.1-Terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-09-22", - last_updated: "2025-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 1.2 }, - limit: { context: 128000, output: 128000 }, - }, - "hf:openai/gpt-oss-120b": { - id: "hf:openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 32768 }, - }, - "hf:moonshotai/Kimi-K2-Thinking": { - id: "hf:moonshotai/Kimi-K2-Thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-07", - last_updated: "2025-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 262144, output: 262144 }, - }, - "hf:moonshotai/Kimi-K2-Instruct-0905": { - id: "hf:moonshotai/Kimi-K2-Instruct-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 1.2 }, - limit: { context: 262144, output: 32768 }, - }, - "hf:moonshotai/Kimi-K2.5": { - id: "hf:moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 262144, output: 65536 }, - }, - "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4": { - id: "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", - name: "Nemotron 3 Super 120B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-03-11", - last_updated: "2026-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1, cache_read: 0.3 }, - limit: { context: 262144, output: 65536 }, - }, - "hf:nvidia/Kimi-K2.5-NVFP4": { - id: "hf:nvidia/Kimi-K2.5-NVFP4", - name: "Kimi K2.5 (NVFP4)", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 262144, output: 65536 }, - }, - "hf:zai-org/GLM-4.7-Flash": { - id: "hf:zai-org/GLM-4.7-Flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-01-18", - last_updated: "2026-01-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4, cache_read: 0.06 }, - limit: { context: 196608, output: 65536 }, - }, - "hf:zai-org/GLM-4.7": { - id: "hf:zai-org/GLM-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 200000, output: 64000 }, - }, - "hf:zai-org/GLM-5.1": { - id: "hf:zai-org/GLM-5.1", - name: "GLM 5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-04-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 1 }, - limit: { context: 196608, output: 65536 }, - }, - "hf:zai-org/GLM-5": { - id: "hf:zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 1 }, - limit: { context: 196608, output: 65536 }, - }, - "hf:zai-org/GLM-4.6": { - id: "hf:zai-org/GLM-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.19 }, - limit: { context: 200000, output: 64000 }, - }, - "hf:moonshotai/Kimi-K2.6": { - id: "hf:moonshotai/Kimi-K2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.95 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - nvidia: { - id: "nvidia", - env: ["NVIDIA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://integrate.api.nvidia.com/v1", - name: "Nvidia", - doc: "https://docs.api.nvidia.com/nim/", - models: { - "black-forest-labs/flux.1-dev": { - id: "black-forest-labs/flux.1-dev", - name: "FLUX.1-dev", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 4096, output: 0 }, - }, - "stepfun-ai/step-3.5-flash": { - id: "stepfun-ai/step-3.5-flash", - name: "Step 3.5 Flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-02", - last_updated: "2026-02-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 16384 }, - }, - "mistralai/codestral-22b-instruct-v0.1": { - id: "mistralai/codestral-22b-instruct-v0.1", - name: "Codestral 22b Instruct V0.1", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-05-29", - last_updated: "2024-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/mistral-large-3-675b-instruct-2512": { - id: "mistralai/mistral-large-3-675b-instruct-2512", - name: "Mistral Large 3 675B Instruct 2512", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/devstral-2-123b-instruct-2512": { - id: "mistralai/devstral-2-123b-instruct-2512", - name: "Devstral-2-123B-Instruct-2512", - family: "devstral", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-08", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/ministral-14b-instruct-2512": { - id: "mistralai/ministral-14b-instruct-2512", - name: "Ministral 3 14B Instruct 2512", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-01", - last_updated: "2025-12-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/mistral-small-3.1-24b-instruct-2503": { - id: "mistralai/mistral-small-3.1-24b-instruct-2503", - name: "Mistral Small 3.1 24b Instruct 2503", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-11", - last_updated: "2025-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/mamba-codestral-7b-v0.1": { - id: "mistralai/mamba-codestral-7b-v0.1", - name: "Mamba Codestral 7b V0.1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-07-16", - last_updated: "2024-07-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "mistralai/mistral-large-2-instruct": { - id: "mistralai/mistral-large-2-instruct", - name: "Mistral Large 2 Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-24", - last_updated: "2024-07-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-medium-4k-instruct": { - id: "microsoft/phi-3-medium-4k-instruct", - name: "Phi 3 Medium 4k Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-05-07", - last_updated: "2024-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 4000, output: 4096 }, - }, - "microsoft/phi-3.5-moe-instruct": { - id: "microsoft/phi-3.5-moe-instruct", - name: "Phi 3.5 Moe Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-08-17", - last_updated: "2024-08-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-4-mini-instruct": { - id: "microsoft/phi-4-mini-instruct", - name: "Phi-4-Mini", - family: "phi", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2025-09-05", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "microsoft/phi-3-small-8k-instruct": { - id: "microsoft/phi-3-small-8k-instruct", - name: "Phi 3 Small 8k Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-05-07", - last_updated: "2024-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8000, output: 4096 }, - }, - "microsoft/phi-3-vision-128k-instruct": { - id: "microsoft/phi-3-vision-128k-instruct", - name: "Phi 3 Vision 128k Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-05-19", - last_updated: "2024-05-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3.5-vision-instruct": { - id: "microsoft/phi-3.5-vision-instruct", - name: "Phi 3.5 Vision Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-08-16", - last_updated: "2024-08-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-small-128k-instruct": { - id: "microsoft/phi-3-small-128k-instruct", - name: "Phi 3 Small 128k Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-05-07", - last_updated: "2024-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-medium-128k-instruct": { - id: "microsoft/phi-3-medium-128k-instruct", - name: "Phi 3 Medium 128k Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-05-07", - last_updated: "2024-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": { - id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", - name: "Nemotron 3 Nano Omni", - family: "nemotron", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-28", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 65536 }, - }, - "nvidia/llama-3.3-nemotron-super-49b-v1": { - id: "nvidia/llama-3.3-nemotron-super-49b-v1", - name: "Llama 3.3 Nemotron Super 49b V1", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-03-16", - last_updated: "2025-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/nemotron-4-340b-instruct": { - id: "nvidia/nemotron-4-340b-instruct", - name: "Nemotron 4 340b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-06-13", - last_updated: "2024-06-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/llama3-chatqa-1.5-70b": { - id: "nvidia/llama3-chatqa-1.5-70b", - name: "Llama3 Chatqa 1.5 70b", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-04-28", - last_updated: "2024-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/llama-3.3-nemotron-super-49b-v1.5": { - id: "nvidia/llama-3.3-nemotron-super-49b-v1.5", - name: "Llama 3.3 Nemotron Super 49b V1.5", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-03-16", - last_updated: "2025-03-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "Nemotron 3 Super", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/parakeet-tdt-0.6b-v2": { - id: "nvidia/parakeet-tdt-0.6b-v2", - name: "Parakeet TDT 0.6B v2", - family: "parakeet", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-01", - release_date: "2024-01-01", - last_updated: "2025-09-05", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 0, output: 4096 }, - }, - "nvidia/nemotron-3-nano-30b-a3b": { - id: "nvidia/nemotron-3-nano-30b-a3b", - name: "nemotron-3-nano-30b-a3b", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/llama-3.1-nemotron-ultra-253b-v1": { - id: "nvidia/llama-3.1-nemotron-ultra-253b-v1", - name: "Llama-3.1-Nemotron-Ultra-253B-v1", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "nvidia/nvidia-nemotron-nano-9b-v2": { - id: "nvidia/nvidia-nemotron-nano-9b-v2", - name: "nvidia-nemotron-nano-9b-v2", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-08-18", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/cosmos-nemotron-34b": { - id: "nvidia/cosmos-nemotron-34b", - name: "Cosmos Nemotron 34B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-01", - release_date: "2024-01-01", - last_updated: "2025-09-05", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "nvidia/llama-embed-nemotron-8b": { - id: "nvidia/llama-embed-nemotron-8b", - name: "Llama Embed Nemotron 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-03", - release_date: "2025-03-18", - last_updated: "2025-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 2048 }, - }, - "nvidia/llama-3.1-nemotron-51b-instruct": { - id: "nvidia/llama-3.1-nemotron-51b-instruct", - name: "Llama 3.1 Nemotron 51b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-22", - last_updated: "2024-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/llama-3.1-nemotron-70b-instruct": { - id: "nvidia/llama-3.1-nemotron-70b-instruct", - name: "Llama 3.1 Nemotron 70b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-10-12", - last_updated: "2024-10-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "nvidia/nemoretriever-ocr-v1": { - id: "nvidia/nemoretriever-ocr-v1", - name: "NeMo Retriever OCR v1", - family: "nemoretriever", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-01", - release_date: "2024-01-01", - last_updated: "2025-09-05", - modalities: { input: ["image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 0, output: 4096 }, - }, - "deepseek-ai/deepseek-r1": { - id: "deepseek-ai/deepseek-r1", - name: "Deepseek R1", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-ai/deepseek-v3.1": { - id: "deepseek-ai/deepseek-v3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-08-20", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek-ai/deepseek-coder-6.7b-instruct": { - id: "deepseek-ai/deepseek-coder-6.7b-instruct", - name: "Deepseek Coder 6.7b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2023-10-29", - last_updated: "2023-10-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-ai/deepseek-v3.2": { - id: "deepseek-ai/deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 163840, output: 65536 }, - }, - "deepseek-ai/deepseek-r1-0528": { - id: "deepseek-ai/deepseek-r1-0528", - name: "Deepseek R1 0528", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-ai/deepseek-v3.1-terminus": { - id: "deepseek-ai/deepseek-v3.1-terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/whisper-large-v3": { - id: "openai/whisper-large-v3", - name: "Whisper Large v3", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2023-09", - release_date: "2023-09-01", - last_updated: "2025-09-05", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 0, output: 4096 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT-OSS-120B", - family: "gpt-oss", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-04", - last_updated: "2025-08-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "minimaxai/minimax-m2.7": { - id: "minimaxai/minimax-m2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-04-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "minimaxai/minimax-m2.1": { - id: "minimaxai/minimax-m2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "minimaxai/minimax-m2.5": { - id: "minimaxai/minimax-m2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "z-ai/glm4.7": { - id: "z-ai/glm4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "z-ai/glm5": { - id: "z-ai/glm5", - name: "GLM5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 202752, output: 131000 }, - }, - "z-ai/glm-5.1": { - id: "z-ai/glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 131072 }, - }, - "meta/llama-4-scout-17b-16e-instruct": { - id: "meta/llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17b 16e Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-02", - release_date: "2025-04-02", - last_updated: "2025-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-3.3-70b-instruct": { - id: "meta/llama-3.3-70b-instruct", - name: "Llama 3.3 70b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-11-26", - last_updated: "2024-11-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama3-8b-instruct": { - id: "meta/llama3-8b-instruct", - name: "Llama3 8b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-04-17", - last_updated: "2024-04-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama3-70b-instruct": { - id: "meta/llama3-70b-instruct", - name: "Llama3 70b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-04-17", - last_updated: "2024-04-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/codellama-70b": { - id: "meta/codellama-70b", - name: "Codellama 70b", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-01-29", - last_updated: "2024-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-3.2-11b-vision-instruct": { - id: "meta/llama-3.2-11b-vision-instruct", - name: "Llama 3.2 11b Vision Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-3.1-70b-instruct": { - id: "meta/llama-3.1-70b-instruct", - name: "Llama 3.1 70b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-16", - last_updated: "2024-07-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-3.2-1b-instruct": { - id: "meta/llama-3.2-1b-instruct", - name: "Llama 3.2 1b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-4-maverick-17b-128e-instruct": { - id: "meta/llama-4-maverick-17b-128e-instruct", - name: "Llama 4 Maverick 17b 128e Instruct", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-02", - release_date: "2025-04-01", - last_updated: "2025-04-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-3.1-405b-instruct": { - id: "meta/llama-3.1-405b-instruct", - name: "Llama 3.1 405b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-16", - last_updated: "2024-07-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen/qwen3-235b-a22b": { - id: "qwen/qwen3-235b-a22b", - name: "Qwen3-235B-A22B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen/qwen2.5-coder-7b-instruct": { - id: "qwen/qwen2.5-coder-7b-instruct", - name: "Qwen2.5 Coder 7b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-17", - last_updated: "2024-09-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen/qwen2.5-coder-32b-instruct": { - id: "qwen/qwen2.5-coder-32b-instruct", - name: "Qwen2.5 Coder 32b Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-11-06", - last_updated: "2024-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen/qwen3.5-397b-a17b": { - id: "qwen/qwen3.5-397b-a17b", - name: "Qwen3.5-397B-A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 8192 }, - }, - "qwen/qwen3-next-80b-a3b-thinking": { - id: "qwen/qwen3-next-80b-a3b-thinking", - name: "Qwen3-Next-80B-A3B-Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen/qwq-32b": { - id: "qwen/qwq-32b", - name: "Qwq 32b", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen/qwen3-next-80b-a3b-instruct": { - id: "qwen/qwen3-next-80b-a3b-instruct", - name: "Qwen3-Next-80B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen/qwen3-coder-480b-a35b-instruct": { - id: "qwen/qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 66536 }, - }, - "google/gemma-2-2b-it": { - id: "google/gemma-2-2b-it", - name: "Gemma 2 2b It", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-16", - last_updated: "2024-07-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-3n-e4b-it": { - id: "google/gemma-3n-e4b-it", - name: "Gemma 3n E4b It", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-06-03", - last_updated: "2025-06-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-3-1b-it": { - id: "google/gemma-3-1b-it", - name: "Gemma 3 1b It", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-10", - last_updated: "2025-03-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/codegemma-7b": { - id: "google/codegemma-7b", - name: "Codegemma 7b", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-03-21", - last_updated: "2024-03-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-4-31b-it": { - id: "google/gemma-4-31b-it", - name: "Gemma-4-31B-IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 16384 }, - }, - "google/gemma-3-12b-it": { - id: "google/gemma-3-12b-it", - name: "Gemma 3 12b It", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/codegemma-1.1-7b": { - id: "google/codegemma-1.1-7b", - name: "Codegemma 1.1 7b", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-04-30", - last_updated: "2024-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-3n-e2b-it": { - id: "google/gemma-3n-e2b-it", - name: "Gemma 3n E2b It", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-06-12", - last_updated: "2025-06-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-2-27b-it": { - id: "google/gemma-2-27b-it", - name: "Gemma 2 27b It", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-06-24", - last_updated: "2024-06-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Gemma-3-27B-IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2024-12-01", - last_updated: "2025-09-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-07", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-instruct": { - id: "moonshotai/kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-01", - release_date: "2025-01-01", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-instruct-0905": { - id: "moonshotai/kimi-k2-instruct-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11", - last_updated: "2025-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/mistral-medium-3.5-128b": { - id: "mistralai/mistral-medium-3.5-128b", - name: "Mistral Medium 3.5 128B", - family: "mistral-medium", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-29", - last_updated: "2026-04-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-ai/deepseek-v4-flash": { - id: "deepseek-ai/deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1048576, output: 393216 }, - }, - "deepseek-ai/deepseek-v4-pro": { - id: "deepseek-ai/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1048576, output: 393216 }, - }, - }, - }, - inference: { - id: "inference", - env: ["INFERENCE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://inference.net/v1", - name: "Inference", - doc: "https://inference.net/models", - models: { - "mistral/mistral-nemo-12b-instruct": { - id: "mistral/mistral-nemo-12b-instruct", - name: "Mistral Nemo 12B Instruct", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.038, output: 0.1 }, - limit: { context: 16000, output: 4096 }, - }, - "meta/llama-3.2-11b-vision-instruct": { - id: "meta/llama-3.2-11b-vision-instruct", - name: "Llama 3.2 11B Vision Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.055, output: 0.055 }, - limit: { context: 16000, output: 4096 }, - }, - "meta/llama-3.2-1b-instruct": { - id: "meta/llama-3.2-1b-instruct", - name: "Llama 3.2 1B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0.01 }, - limit: { context: 16000, output: 4096 }, - }, - "meta/llama-3.2-3b-instruct": { - id: "meta/llama-3.2-3b-instruct", - name: "Llama 3.2 3B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.02 }, - limit: { context: 16000, output: 4096 }, - }, - "meta/llama-3.1-8b-instruct": { - id: "meta/llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.025, output: 0.025 }, - limit: { context: 16000, output: 4096 }, - }, - "qwen/qwen-2.5-7b-vision-instruct": { - id: "qwen/qwen-2.5-7b-vision-instruct", - name: "Qwen 2.5 7B Vision Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 125000, output: 4096 }, - }, - "qwen/qwen3-embedding-4b": { - id: "qwen/qwen3-embedding-4b", - name: "Qwen 3 Embedding 4B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0 }, - limit: { context: 32000, output: 2048 }, - }, - "google/gemma-3": { - id: "google/gemma-3", - name: "Google Gemma 3", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.3 }, - limit: { context: 125000, output: 4096 }, - }, - "osmosis/osmosis-structure-0.6b": { - id: "osmosis/osmosis-structure-0.6b", - name: "Osmosis Structure 0.6B", - family: "osmosis", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 4000, output: 2048 }, - }, - }, - }, - inception: { - id: "inception", - env: ["INCEPTION_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.inceptionlabs.ai/v1/", - name: "Inception", - doc: "https://platform.inceptionlabs.ai/docs", - models: { - "mercury-edit-2": { - id: "mercury-edit-2", - name: "Mercury Edit 2", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 8192 }, - }, - "mercury-2": { - id: "mercury-2", - name: "Mercury 2", - family: "mercury", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01-01", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 50000 }, - }, - }, - }, - openai: { - id: "openai", - env: ["OPENAI_API_KEY"], - npm: "@ai-sdk/openai", - name: "OpenAI", - doc: "https://platform.openai.com/docs/models", - models: { - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-4o-2024-05-13": { - id: "gpt-4o-2024-05-13", - name: "GPT-4o (2024-05-13)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 15 }, - limit: { context: 128000, output: 4096 }, - }, - "o1-mini": { - id: "o1-mini", - name: "o1-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 128000, output: 65536 }, - }, - "gpt-5.2-pro": { - id: "gpt-5.2-pro", - name: "GPT-5.2 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "text-embedding-3-large": { - id: "text-embedding-3-large", - name: "text-embedding-3-large", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-01", - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0 }, - limit: { context: 8191, output: 3072 }, - }, - "gpt-5.3-chat-latest": { - id: "gpt-5.3-chat-latest", - name: "GPT-5.3 Chat (latest)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - experimental: { - modes: { - fast: { - cost: { input: 12.5, output: 75, cache_read: 1.25 }, - provider: { body: { service_tier: "priority" } }, - }, - }, - }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-4-turbo": { - id: "gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "text-embedding-ada-002": { - id: "text-embedding-ada-002", - name: "text-embedding-ada-002", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2022-12", - release_date: "2022-12-15", - last_updated: "2022-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "o3-pro": { - id: "o3-pro", - name: "o3-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-06-10", - last_updated: "2025-06-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 80 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "o4-mini-deep-research": { - id: "o4-mini-deep-research", - name: "o4-mini-deep-research", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-06-26", - last_updated: "2024-06-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - experimental: { - modes: { - fast: { - cost: { input: 1.5, output: 9, cache_read: 0.15 }, - provider: { body: { service_tier: "priority" } }, - }, - }, - }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-image-1": { - id: "gpt-image-1", - name: "gpt-image-1", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-24", - last_updated: "2025-04-24", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 0, input: 0, output: 0 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.2-chat-latest": { - id: "gpt-5.2-chat-latest", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "o1-preview": { - id: "o1-preview", - name: "o1-preview", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-4o-2024-08-06": { - id: "gpt-4o-2024-08-06", - name: "GPT-4o (2024-08-06)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-08-06", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-image-1-mini": { - id: "gpt-image-1-mini", - name: "gpt-image-1-mini", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-09-26", - last_updated: "2025-09-26", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 0, input: 0, output: 0 }, - }, - o1: { - id: "o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-3.5-turbo": { - id: "gpt-3.5-turbo", - name: "GPT-3.5-turbo", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2021-09-01", - release_date: "2023-03-01", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5, cache_read: 1.25 }, - limit: { context: 16385, output: 4096 }, - }, - "o3-deep-research": { - id: "o3-deep-research", - name: "o3-deep-research", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-06-26", - last_updated: "2024-06-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 40, cache_read: 2.5 }, - limit: { context: 200000, output: 100000 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "text-embedding-3-small": { - id: "text-embedding-3-small", - name: "text-embedding-3-small", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2024-01", - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8191, output: 1536 }, - }, - "o1-pro": { - id: "o1-pro", - name: "o1-pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2025-03-19", - last_updated: "2025-03-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 150, output: 600 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-4": { - id: "gpt-4", - name: "GPT-4", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-11", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 60 }, - limit: { context: 8192, output: 8192 }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "GPT-5-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - experimental: { - modes: { - fast: { cost: { input: 5, output: 30, cache_read: 0.5 }, provider: { body: { service_tier: "priority" } } }, - }, - }, - }, - "gpt-5.1-chat-latest": { - id: "gpt-5.1-chat-latest", - name: "GPT-5.1 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.3-codex-spark": { - id: "gpt-5.3-codex-spark", - name: "GPT-5.3 Codex Spark", - family: "gpt-codex-spark", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, input: 100000, output: 32000 }, - }, - "chatgpt-image-latest": { - id: "chatgpt-image-latest", - name: "chatgpt-image-latest", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 0, input: 0, output: 0 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "GPT-4.1 nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03 }, - limit: { context: 1047576, output: 32768 }, - }, - o3: { - id: "o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, input: 272000, output: 272000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5-chat-latest": { - id: "gpt-5-chat-latest", - name: "GPT-5 Chat (latest)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-image-1.5": { - id: "gpt-image-1.5", - name: "gpt-image-1.5", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 0, input: 0, output: 0 }, - }, - "gpt-5.5-pro": { - id: "gpt-5.5-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-4o-2024-11-20": { - id: "gpt-4o-2024-11-20", - name: "GPT-4o (2024-11-20)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-11-20", - last_updated: "2024-11-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - }, - }, - requesty: { - id: "requesty", - env: ["REQUESTY_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://router.requesty.ai/v1", - name: "Requesty", - doc: "https://requesty.ai/solution/llm-routing/models", - models: { - "xai/grok-4-fast": { - id: "xai/grok-4-fast", - name: "Grok 4 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05, cache_write: 0.2 }, - limit: { context: 2000000, output: 64000 }, - }, - "xai/grok-4": { - id: "xai/grok-4", - name: "Grok 4", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-09", - last_updated: "2025-09-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75, cache_write: 3 }, - limit: { context: 256000, output: 64000 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "GPT-5.1-Codex-Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 9, cache_read: 0.11 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-chat": { - id: "openai/gpt-5-chat", - name: "GPT-5 Chat (latest)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT-5.2 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 128000, output: 32000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.01 }, - limit: { context: 16000, output: 4000 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT-5.3-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.1-chat": { - id: "openai/gpt-5.1-chat", - name: "GPT-5.1 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "o4 Mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT-5.1-Codex-Mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 100000 }, - }, - "openai/gpt-5-image": { - id: "openai/gpt-5-image", - name: "GPT-5 Image", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-10-14", - last_updated: "2025-10-14", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 5, output: 10, cache_read: 1.25 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.1": { - id: "openai/gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, cache_read: 30 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "audio", "image", "video"], output: ["text", "audio", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT-4.1 Mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "google/gemini-3-flash-preview": { - id: "google/gemini-3-flash-preview", - name: "Gemini 3 Flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3-pro-preview": { - id: "google/gemini-3-pro-preview", - name: "Gemini 3 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, cache_write: 4.5 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, cache_write: 0.55 }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic/claude-haiku-4-5": { - id: "anthropic/claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-01", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 62000 }, - }, - "anthropic/claude-sonnet-4-6": { - id: "anthropic/claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-3-7-sonnet": { - id: "anthropic/claude-3-7-sonnet", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-01", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4-5": { - id: "anthropic/claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-opus-4-6": { - id: "anthropic/claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "openai/gpt-5.2-chat": { - id: "openai/gpt-5.2-chat", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, output: 272000 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.31, - cache_write: 2.375, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "anthropic/claude-opus-4-1": { - id: "anthropic/claude-opus-4-1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4-5": { - id: "anthropic/claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - }, - }, - digitalocean: { - id: "digitalocean", - env: ["DIGITALOCEAN_ACCESS_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://inference.do-ai.run/v1", - name: "DigitalOcean", - doc: "https://docs.digitalocean.com/products/gradient-ai-platform/details/models/", - models: { - "openai-gpt-4o-mini": { - id: "openai-gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.075 }, - limit: { context: 128000, output: 16384 }, - }, - "multi-qa-mpnet-base-dot-v1": { - id: "multi-qa-mpnet-base-dot-v1", - name: "Multi-QA-mpnet-base-dot-v1", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2021-08-30", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.009, output: 0 }, - limit: { context: 512, output: 768 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.7 }, - limit: { context: 262144, output: 32768 }, - }, - "nemotron-3-nano-omni": { - id: "nemotron-3-nano-omni", - name: "Nemotron Nano 3 Omni", - family: "nemotron", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-28", - last_updated: "2026-04-30", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 0.9 }, - limit: { context: 65536, output: 65536 }, - }, - "llama3-8b-instruct": { - id: "llama3-8b-instruct", - name: "Llama 3.1 Instruct (8B)", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.198, output: 0.198 }, - limit: { context: 131072, output: 131072 }, - }, - "anthropic-claude-opus-4.7": { - id: "anthropic-claude-opus-4.7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic-claude-sonnet-4": { - id: "anthropic-claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.3, cache_write: 3.75 }, - }, - limit: { context: 1000000, output: 64000 }, - }, - "wan2-2-t2v-a14b": { - id: "wan2-2-t2v-a14b", - name: "Wan2.2-T2V-A14B", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-07-28", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["video"] }, - open_weights: true, - cost: { input: 0.6, output: 0 }, - limit: { context: 100, output: 1 }, - }, - "qwen-2.5-14b-instruct": { - id: "qwen-2.5-14b-instruct", - name: "Qwen 2.5 14B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 131072, output: 131072 }, - }, - "openai-gpt-5.4": { - id: "openai-gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen 3.5 397B A17B", - family: "qwen3.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 3.5 }, - limit: { context: 262144, output: 81920 }, - }, - "openai-o3": { - id: "openai-o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "e5-large-v2": { - id: "e5-large-v2", - name: "E5 Large v2", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-05-19", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0 }, - limit: { context: 512, output: 1024 }, - }, - "openai-gpt-5.2-pro": { - id: "openai-gpt-5.2-pro", - name: "GPT-5.2 pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, output: 128000 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - release_date: "2026-02-11", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 202752, output: 128000 }, - }, - "openai-gpt-5.4-nano": { - id: "openai-gpt-5.4-nano", - name: "GPT-5.4 nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, output: 128000 }, - }, - "mistral-7b-instruct-v0.3": { - id: "mistral-7b-instruct-v0.3", - name: "Mistral 7B Instruct v0.3", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-05-22", - last_updated: "2024-05-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 32768, output: 32768 }, - }, - "llama3.3-70b-instruct": { - id: "llama3.3-70b-instruct", - name: "Llama 3.3 Instruct 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.65, output: 0.65 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-3-14B": { - id: "mistral-3-14B", - name: "Ministral 3 14B Instruct", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-15", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 262144, output: 128000 }, - }, - "deepseek-r1-distill-llama-70b": { - id: "deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-30", - last_updated: "2025-01-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.99, output: 0.99 }, - limit: { context: 131072, output: 32768 }, - }, - "alibaba-qwen3-32b": { - id: "alibaba-qwen3-32b", - name: "Qwen3-32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.55 }, - limit: { context: 131000, output: 40960 }, - }, - "anthropic-claude-opus-4.5": { - id: "anthropic-claude-opus-4.5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "openai-o1": { - id: "openai-o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "anthropic-claude-3-opus": { - id: "anthropic-claude-3-opus", - name: "Claude 3 Opus", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08", - release_date: "2024-02-29", - last_updated: "2024-02-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 4096 }, - status: "deprecated", - }, - "stable-diffusion-3.5-large": { - id: "stable-diffusion-3.5-large", - name: "Stable Diffusion 3.5 Large", - family: "stable-diffusion", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-10-22", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["image"] }, - open_weights: true, - cost: { input: 0.08, output: 0 }, - limit: { context: 256, output: 1 }, - }, - "openai-gpt-5-nano": { - id: "openai-gpt-5-nano", - name: "GPT-5 nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, output: 128000 }, - }, - "llama-4-maverick": { - id: "llama-4-maverick", - name: "Llama 4 Maverick 17B 128E Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2026-04-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.87 }, - limit: { context: 1000000, output: 16384 }, - }, - "anthropic-claude-4.5-sonnet": { - id: "anthropic-claude-4.5-sonnet", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.3, cache_write: 3.75 }, - }, - limit: { context: 1000000, output: 64000 }, - }, - "qwen3-embedding-0.6b": { - id: "qwen3-embedding-0.6b", - name: "Qwen3 Embedding 0.6B", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06-03", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0 }, - limit: { context: 8000, output: 1024 }, - status: "beta", - }, - "anthropic-claude-4.5-haiku": { - id: "anthropic-claude-4.5-haiku", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "gte-large-en-v1.5": { - id: "gte-large-en-v1.5", - name: "GTE Large (v1.5)", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03-27", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0 }, - limit: { context: 8192, output: 1024 }, - }, - "openai-gpt-4.1": { - id: "openai-gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "anthropic-claude-3.5-haiku": { - id: "anthropic-claude-3.5-haiku", - name: "Claude 3.5 Haiku", - family: "claude-haiku", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-11-05", - last_updated: "2024-11-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - status: "deprecated", - }, - "openai-gpt-5.2": { - id: "openai-gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "deepseek-3.2": { - id: "deepseek-3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2025-12-02", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.6 }, - limit: { context: 128000, output: 64000 }, - }, - "nemotron-3-nano-30b": { - id: "nemotron-3-nano-30b", - name: "Nemotron 3 Nano 30B A3B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "anthropic-claude-opus-4": { - id: "anthropic-claude-opus-4", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "openai-gpt-oss-20b": { - id: "openai-gpt-oss-20b", - name: "gpt-oss-20b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-08-05", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.45 }, - limit: { context: 131072, output: 131072 }, - }, - "qwen3-coder-flash": { - id: "qwen3-coder-flash", - name: "Qwen3 Coder Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 1.7 }, - limit: { context: 262144, output: 65536 }, - }, - "openai-o3-mini": { - id: "openai-o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "openai-gpt-oss-120b": { - id: "openai-gpt-oss-120b", - name: "gpt-oss-120b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-08-05", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.7 }, - limit: { context: 131072, output: 131072 }, - }, - "gemma-4-31B-it": { - id: "gemma-4-31B-it", - name: "Gemma 4 31B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-04-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.5 }, - limit: { context: 256000, output: 8192 }, - }, - "nemotron-nano-12b-v2-vl": { - id: "nemotron-nano-12b-v2-vl", - name: "Nemotron Nano 12B v2 VL", - family: "nemotron", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-01", - last_updated: "2026-04-30", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 128000, output: 16384 }, - }, - "anthropic-claude-4.1-opus": { - id: "anthropic-claude-4.1-opus", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4 }, - limit: { context: 262144, output: 262144 }, - }, - "openai-gpt-image-2": { - id: "openai-gpt-image-2", - name: "GPT Image 2", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-24", - last_updated: "2025-04-24", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "anthropic-claude-4.6-sonnet": { - id: "anthropic-claude-4.6-sonnet", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.3, cache_write: 3.75 }, - }, - limit: { context: 1000000, output: 64000 }, - }, - "openai-gpt-5-mini": { - id: "openai-gpt-5-mini", - name: "GPT-5 mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "anthropic-claude-haiku-4.5": { - id: "anthropic-claude-haiku-4.5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48 }, - limit: { context: 1048576, output: 393216 }, - }, - "ministral-3-8b-instruct-2512": { - id: "ministral-3-8b-instruct-2512", - name: "Ministral 3 8B", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-15", - last_updated: "2025-12-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 262144, output: 262144 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax-m2.5", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2026-02-12", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 128000 }, - status: "beta", - }, - "openai-gpt-image-1": { - id: "openai-gpt-image-1", - name: "GPT Image 1", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-24", - last_updated: "2025-04-24", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - cost: { input: 5, output: 40, cache_read: 1.25 }, - limit: { context: 0, output: 0 }, - }, - "openai-gpt-5.5": { - id: "openai-gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1000000, output: 128000 }, - }, - "nvidia-nemotron-3-super-120b": { - id: "nvidia-nemotron-3-super-120b", - name: "Nemotron-3-Super-120B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-02", - release_date: "2026-03-11", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.65 }, - limit: { context: 256000, output: 32768 }, - status: "beta", - }, - "openai-gpt-5.4-pro": { - id: "openai-gpt-5.4-pro", - name: "GPT-5.4 pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 400000, output: 128000 }, - }, - "all-mini-lm-l6-v2": { - id: "all-mini-lm-l6-v2", - name: "All-MiniLM-L6-v2", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2021-08-30", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.009, output: 0 }, - limit: { context: 256, output: 384 }, - }, - "bge-m3": { - id: "bge-m3", - name: "BGE M3", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-01-30", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0 }, - limit: { context: 8192, output: 1024 }, - }, - "openai-gpt-5.1-codex-max": { - id: "openai-gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "anthropic-claude-opus-4.6": { - id: "anthropic-claude-opus-4.6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 0.5, cache_write: 6.25 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "openai-gpt-4o": { - id: "openai-gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "openai-gpt-5.4-mini": { - id: "openai-gpt-5.4-mini", - name: "GPT-5.4 mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, output: 128000 }, - }, - "openai-gpt-5": { - id: "openai-gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "arcee-trinity-large-thinking": { - id: "arcee-trinity-large-thinking", - name: "Trinity Large Thinking", - family: "trinity", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.9, cache_read: 0.06 }, - limit: { context: 256000, output: 128000 }, - status: "beta", - }, - "mistral-nemo-instruct-2407": { - id: "mistral-nemo-instruct-2407", - name: "Mistral Nemo Instruct", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - status: "deprecated", - }, - "deepseek-v3": { - id: "deepseek-v3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-12-26", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - limit: { context: 163840, output: 131072 }, - }, - "bge-reranker-v2-m3": { - id: "bge-reranker-v2-m3", - name: "BGE Reranker v2 M3", - family: "bge", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03-12", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.01, output: 0 }, - limit: { context: 8192, output: 1 }, - }, - "anthropic-claude-3.7-sonnet": { - id: "anthropic-claude-3.7-sonnet", - name: "Claude 3.7 Sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - status: "deprecated", - }, - "qwen3-tts-voicedesign": { - id: "qwen3-tts-voicedesign", - name: "Qwen3 TTS VoiceDesign", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2026-04-21", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: true, - limit: { context: 32768, output: 1 }, - }, - "openai-gpt-image-1.5": { - id: "openai-gpt-image-1.5", - name: "GPT Image 1.5", - family: "gpt-image", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-11-25", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["image"] }, - open_weights: false, - cost: { input: 5, output: 10, cache_read: 1 }, - limit: { context: 0, output: 0 }, - }, - "openai-gpt-5.3-codex": { - id: "openai-gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "anthropic-claude-3.5-sonnet": { - id: "anthropic-claude-3.5-sonnet", - name: "Claude 3.5 Sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-06-20", - last_updated: "2024-10-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - status: "deprecated", - }, - "fal-ai/fast-sdxl": { - id: "fal-ai/fast-sdxl", - name: "Fast SDXL", - family: "stable-diffusion", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-07-26", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["image"] }, - open_weights: true, - limit: { context: 0, output: 0 }, - }, - "fal-ai/flux/schnell": { - id: "fal-ai/flux/schnell", - name: "FLUX.1 [schnell]", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08-01", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["image"] }, - open_weights: true, - limit: { context: 0, output: 0 }, - }, - "fal-ai/elevenlabs/tts/multilingual-v2": { - id: "fal-ai/elevenlabs/tts/multilingual-v2", - name: "ElevenLabs Multilingual TTS v2", - family: "elevenlabs", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-08-22", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "fal-ai/stable-audio-25/text-to-audio": { - id: "fal-ai/stable-audio-25/text-to-audio", - name: "Stable Audio 2.5 (Text-to-Audio)", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-10-08", - last_updated: "2026-04-16", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - }, - }, - vultr: { - id: "vultr", - env: ["VULTR_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.vultrinference.com/v1", - name: "Vultr", - doc: "https://api.vultrinference.com/", - models: { - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-02-11", - last_updated: "2025-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 194000, output: 4096 }, - }, - "GLM-5-FP8": { - id: "GLM-5-FP8", - name: "GLM 5 FP8", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.85, output: 3.1 }, - limit: { context: 200000, output: 131072 }, - }, - "DeepSeek-V3.2": { - id: "DeepSeek-V3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 1.65 }, - limit: { context: 127000, output: 4096 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 129000, output: 4096 }, - }, - "Kimi-K2.5": { - id: "Kimi-K2.5", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.75 }, - limit: { context: 254000, output: 32768 }, - }, - }, - }, - "alibaba-coding-plan-cn": { - id: "alibaba-coding-plan-cn", - env: ["ALIBABA_CODING_PLAN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://coding.dashscope.aliyuncs.com/v1", - name: "Alibaba Coding Plan (China)", - doc: "https://help.aliyun.com/zh/model-studio/coding-plan", - models: { - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 16384 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 16384 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 196608, output: 24576 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - "qwen3-max-2026-01-23": { - id: "qwen3-max-2026-01-23", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-23", - last_updated: "2026-01-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-03", - last_updated: "2026-02-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3.5-plus": { - id: "qwen3.5-plus", - name: "Qwen3.5 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 65536 }, - }, - }, - }, - mistral: { - id: "mistral", - env: ["MISTRAL_API_KEY"], - npm: "@ai-sdk/mistral", - name: "Mistral", - doc: "https://docs.mistral.ai/getting-started/models/", - models: { - "mistral-small-latest": { - id: "mistral-small-latest", - name: "Mistral Small (latest)", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 256000, output: 256000 }, - }, - "mistral-nemo": { - id: "mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-large-2512": { - id: "mistral-large-2512", - name: "Mistral Large 3", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 262144, output: 262144 }, - }, - "labs-devstral-small-2512": { - id: "labs-devstral-small-2512", - name: "Devstral Small 2", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 256000 }, - }, - "devstral-2512": { - id: "devstral-2512", - name: "Devstral 2", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "magistral-medium-latest": { - id: "magistral-medium-latest", - name: "Magistral Medium (latest)", - family: "magistral-medium", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-03-17", - last_updated: "2025-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 5 }, - limit: { context: 128000, output: 16384 }, - }, - "open-mixtral-8x7b": { - id: "open-mixtral-8x7b", - name: "Mixtral 8x7B", - family: "mixtral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-01", - release_date: "2023-12-11", - last_updated: "2023-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 0.7 }, - limit: { context: 32000, output: 32000 }, - }, - "pixtral-large-latest": { - id: "pixtral-large-latest", - name: "Pixtral Large (latest)", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2024-11-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-large-2411": { - id: "mistral-large-2411", - name: "Mistral Large 2.1", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2024-11-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 131072, output: 16384 }, - }, - "codestral-latest": { - id: "codestral-latest", - name: "Codestral (latest)", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-05-29", - last_updated: "2025-01-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 4096 }, - }, - "mistral-large-latest": { - id: "mistral-large-latest", - name: "Mistral Large (latest)", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 262144, output: 262144 }, - }, - "mistral-small-2506": { - id: "mistral-small-2506", - name: "Mistral Small 3.2", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-06-20", - last_updated: "2025-06-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "pixtral-12b": { - id: "pixtral-12b", - name: "Pixtral 12B", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-09-01", - last_updated: "2024-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 128000 }, - }, - "ministral-8b-latest": { - id: "ministral-8b-latest", - name: "Ministral 8B (latest)", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-embed": { - id: "mistral-embed", - name: "Mistral Embed", - family: "mistral-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-12-11", - last_updated: "2023-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8000, output: 3072 }, - }, - "magistral-small": { - id: "magistral-small", - name: "Magistral Small", - family: "magistral-small", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-03-17", - last_updated: "2025-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-small-2603": { - id: "mistral-small-2603", - name: "Mistral Small 4", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 256000, output: 256000 }, - }, - "ministral-3b-latest": { - id: "ministral-3b-latest", - name: "Ministral 3B (latest)", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 128000, output: 128000 }, - }, - "open-mixtral-8x22b": { - id: "open-mixtral-8x22b", - name: "Mixtral 8x22B", - family: "mixtral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-17", - last_updated: "2024-04-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 64000, output: 64000 }, - }, - "mistral-medium-2604": { - id: "mistral-medium-2604", - name: "Mistral Medium 3.5", - family: "mistral-medium", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-29", - last_updated: "2026-04-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.5, output: 7.5 }, - limit: { context: 262144, output: 262144 }, - }, - "devstral-small-2505": { - id: "devstral-small-2505", - name: "Devstral Small 2505", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 128000 }, - }, - "devstral-medium-2507": { - id: "devstral-medium-2507", - name: "Devstral Medium", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 128000, output: 128000 }, - }, - "open-mistral-7b": { - id: "open-mistral-7b", - name: "Mistral 7B", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2023-09-27", - last_updated: "2023-09-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.25 }, - limit: { context: 8000, output: 8000 }, - }, - "devstral-medium-latest": { - id: "devstral-medium-latest", - name: "Devstral 2 (latest)", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "mistral-medium-2505": { - id: "mistral-medium-2505", - name: "Mistral Medium 3", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131072, output: 131072 }, - }, - "devstral-small-2507": { - id: "devstral-small-2507", - name: "Devstral Small", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral-medium-2508": { - id: "mistral-medium-2508", - name: "Mistral Medium 3.1", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-08-12", - last_updated: "2025-08-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "mistral-medium-latest": { - id: "mistral-medium-latest", - name: "Mistral Medium (latest)", - family: "mistral-medium", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-29", - last_updated: "2026-04-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.5, output: 7.5 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - ovhcloud: { - id: "ovhcloud", - env: ["OVHCLOUD_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1", - name: "OVHcloud AI Endpoints", - doc: "https://www.ovhcloud.com/en/public-cloud/ai-endpoints/catalog//", - models: { - "meta-llama-3_3-70b-instruct": { - id: "meta-llama-3_3-70b-instruct", - name: "Meta-Llama-3_3-70B-Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-01", - last_updated: "2025-04-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.74, output: 0.74 }, - limit: { context: 131072, output: 131072 }, - }, - "mistral-7b-instruct-v0.3": { - id: "mistral-7b-instruct-v0.3", - name: "Mistral-7B-Instruct-v0.3", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-01", - last_updated: "2025-04-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.11 }, - limit: { context: 65536, output: 65536 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3-32B", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-16", - last_updated: "2025-07-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.25 }, - limit: { context: 32768, output: 32768 }, - }, - "qwen2.5-vl-72b-instruct": { - id: "qwen2.5-vl-72b-instruct", - name: "Qwen2.5-VL-72B-Instruct", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-03-31", - last_updated: "2025-03-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.01, output: 1.01 }, - limit: { context: 32768, output: 32768 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3-Coder-30B-A3B-Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-28", - last_updated: "2025-10-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.26 }, - limit: { context: 262144, output: 262144 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "gpt-oss-20b", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.18 }, - limit: { context: 131072, output: 131072 }, - }, - "mistral-small-3.2-24b-instruct-2506": { - id: "mistral-small-3.2-24b-instruct-2506", - name: "Mistral-Small-3.2-24B-Instruct-2506", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-16", - last_updated: "2025-07-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.31 }, - limit: { context: 131072, output: 131072 }, - }, - "qwen3.5-9b": { - id: "qwen3.5-9b", - name: "Qwen3.5-9B", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "gpt-oss-120b", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.47 }, - limit: { context: 131072, output: 131072 }, - }, - "mistral-nemo-instruct-2407": { - id: "mistral-nemo-instruct-2407", - name: "Mistral-Nemo-Instruct-2407", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-11-20", - last_updated: "2024-11-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.14 }, - limit: { context: 65536, output: 65536 }, - }, - "llama-3.1-8b-instruct": { - id: "llama-3.1-8b-instruct", - name: "Llama-3.1-8B-Instruct", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-06-11", - last_updated: "2025-06-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.11 }, - limit: { context: 131072, output: 131072 }, - }, - }, - }, - friendli: { - id: "friendli", - env: ["FRIENDLI_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.friendli.ai/serverless/v1", - name: "Friendli", - doc: "https://friendli.ai/docs/guides/serverless_endpoints/introduction", - models: { - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-29", - last_updated: "2026-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.8 }, - limit: { context: 262144, output: 262144 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202752, output: 202752 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.5 }, - limit: { context: 202752, output: 202752 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-08-01", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 0.6 }, - limit: { context: 131072, output: 131072 }, - }, - "meta-llama/Llama-3.1-8B-Instruct": { - id: "meta-llama/Llama-3.1-8B-Instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-08-01", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8000 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 196608, output: 196608 }, - }, - }, - }, - cortecs: { - id: "cortecs", - env: ["CORTECS_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.cortecs.ai/v1", - name: "Cortecs", - doc: "https://api.cortecs.ai/v1/models", - models: { - "minimax-m2.7": { - id: "minimax-m2.7", - name: "MiniMax-m2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.47, output: 1.4 }, - limit: { context: 202752, output: 196072 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.09, output: 5.43 }, - limit: { context: 200000, output: 200000 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.062, output: 0.408 }, - limit: { context: 131000, output: 131000 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.76 }, - limit: { context: 256000, output: 256000 }, - }, - "deepseek-v3-0324": { - id: "deepseek-v3-0324", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.551, output: 1.654 }, - limit: { context: 128000, output: 128000 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.23 }, - limit: { context: 198000, output: 198000 }, - }, - "claude-opus4-7": { - id: "claude-opus4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5.6, output: 27.99, cache_read: 0.56, cache_write: 6.99 }, - limit: { context: 1000000, output: 128000 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM 5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.08, output: 3.44 }, - limit: { context: 202752, output: 202752 }, - }, - "nova-pro-v1": { - id: "nova-pro-v1", - name: "Nova Pro 1.0", - family: "nova-pro", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.016, output: 4.061 }, - limit: { context: 300000, output: 5000 }, - }, - "devstral-2512": { - id: "devstral-2512", - name: "Devstral 2 2512", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262000, output: 262000 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.099, output: 0.33 }, - limit: { context: 16384, output: 16384 }, - }, - "codestral-2508": { - id: "codestral-2508", - name: "Codestral 2508", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9, cache_read: 0.03 }, - limit: { context: 256000, output: 256000 }, - }, - "claude-4-5-sonnet": { - id: "claude-4-5-sonnet", - name: "Claude 4.5 Sonnet", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3.259, output: 16.296 }, - limit: { context: 200000, output: 200000 }, - }, - "kimi-k2-instruct": { - id: "kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-07-11", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.551, output: 2.646 }, - limit: { context: 131000, output: 131000 }, - }, - "nemotron-3-super-120b-a12b": { - id: "nemotron-3-super-120b-a12b", - name: "Nemotron 3 Super 120B A12B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.266, output: 0.799 }, - limit: { context: 262144, output: 262144 }, - }, - "minimax-m2": { - id: "minimax-m2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-11", - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.39, output: 1.57 }, - limit: { context: 400000, output: 400000 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.654, output: 11.024 }, - limit: { context: 1048576, output: 65535 }, - }, - "claude-opus4-6": { - id: "claude-opus4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5.98, output: 29.89 }, - limit: { context: 1000000, output: 1000000 }, - }, - "devstral-small-2512": { - id: "devstral-small-2512", - name: "Devstral Small 2 2512", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262000, output: 262000 }, - }, - "minimax-m2.1": { - id: "minimax-m2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.34, output: 1.34 }, - limit: { context: 196000, output: 196000 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-14", - last_updated: "2026-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.31, output: 4.1, cache_read: 0.24 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM 4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-29", - last_updated: "2025-07-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.67, output: 2.46 }, - limit: { context: 131072, output: 131072 }, - }, - "claude-opus4-5": { - id: "claude-opus4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5.98, output: 29.89 }, - limit: { context: 200000, output: 200000 }, - }, - "claude-sonnet-4": { - id: "claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3.307, output: 16.536 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-next-80b-a3b-thinking": { - id: "qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-11", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.164, output: 1.311 }, - limit: { context: 128000, output: 128000 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-01", - last_updated: "2025-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 1.34 }, - limit: { context: 131072, output: 131072 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.81, output: 3.54, cache_read: 0.2 }, - limit: { context: 256000, output: 256000 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "Qwen3 Coder Next 80B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-02-04", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.158, output: 0.84 }, - limit: { context: 256000, output: 65536 }, - }, - "claude-4-6-sonnet": { - id: "claude-4-6-sonnet", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3.59, output: 17.92 }, - limit: { context: 1000000, output: 1000000 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.441, output: 1.984 }, - limit: { context: 262000, output: 262000 }, - }, - "mixtral-8x7B-instruct-v0.1": { - id: "mixtral-8x7B-instruct-v0.1", - name: "Mixtral 8x7B Instruct v0.1", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-09", - release_date: "2023-12-11", - last_updated: "2023-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.438, output: 0.68 }, - limit: { context: 32000, output: 32000 }, - }, - "hermes-4-70b": { - id: "hermes-4-70b", - name: "Hermes 4 70B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.116, output: 0.358 }, - limit: { context: 128000, output: 128000 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.32, output: 1.18 }, - limit: { context: 196608, output: 196608 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.266, output: 0.444 }, - limit: { context: 163840, output: 163840 }, - }, - "intellect-3": { - id: "intellect-3", - name: "INTELLECT 3", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-26", - last_updated: "2025-11-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.219, output: 1.202 }, - limit: { context: 128000, output: 128000 }, - }, - "glm-4.7-flash": { - id: "glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-08", - last_updated: "2025-08-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.53 }, - limit: { context: 203000, output: 203000 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT Oss 120b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-01", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - }, - "qwen-2.5-72b-instruct": { - id: "qwen-2.5-72b-instruct", - name: "Qwen2.5 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.062, output: 0.231 }, - limit: { context: 33000, output: 33000 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek R1 0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.585, output: 2.307 }, - limit: { context: 164000, output: 164000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT 4.1", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.354, output: 9.417 }, - limit: { context: 1047576, output: 32768 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.656, output: 2.731 }, - limit: { context: 262000, output: 262000 }, - }, - "llama-3.1-405b-instruct": { - id: "llama-3.1-405b-instruct", - name: "Llama 3.1 405B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - }, - "qwen3.5-122b-a10b": { - id: "qwen3.5-122b-a10b", - name: "Qwen3.5 122B A10B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.444, output: 3.106 }, - limit: { context: 262144, output: 262144 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.089, output: 0.275 }, - limit: { context: 131000, output: 131000 }, - }, - "mistral-large-2512": { - id: "mistral-large-2512", - name: "Mistral Large 3 2512", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5, cache_read: 0.05 }, - limit: { context: 256000, output: 256000 }, - }, - "qwen3.5-397b-a17b": { - id: "qwen3.5-397b-a17b", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 250000, output: 250000 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.133, output: 0.266, cache_read: 0.028 }, - limit: { context: 1048576, output: 384000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.553, output: 3.106, cache_read: 0.145 }, - limit: { context: 1048576, output: 384000 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.053, output: 0.222 }, - limit: { context: 262000, output: 262000 }, - }, - }, - }, - siliconflow: { - id: "siliconflow", - env: ["SILICONFLOW_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.siliconflow.com/v1", - name: "SiliconFlow", - doc: "https://cloud.siliconflow.com/models", - models: { - "nex-agi/DeepSeek-V3.1-Nex-N1": { - id: "nex-agi/DeepSeek-V3.1-Nex-N1", - name: "nex-agi/DeepSeek-V3.1-Nex-N1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-01", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen2.5-VL-72B-Instruct": { - id: "Qwen/Qwen2.5-VL-72B-Instruct", - name: "Qwen/Qwen2.5-VL-72B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-28", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 131000, output: 4000 }, - }, - "Qwen/Qwen3-VL-32B-Thinking": { - id: "Qwen/Qwen3-VL-32B-Thinking", - name: "Qwen/Qwen3-VL-32B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-21", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-30B-A3B-Thinking-2507": { - id: "Qwen/Qwen3-30B-A3B-Thinking-2507", - name: "Qwen/Qwen3-30B-A3B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.3 }, - limit: { context: 262000, output: 131000 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Thinking": { - id: "Qwen/Qwen3-VL-235B-A22B-Thinking", - name: "Qwen/Qwen3-VL-235B-A22B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.45, output: 3.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-7B-Instruct": { - id: "Qwen/Qwen2.5-7B-Instruct", - name: "Qwen/Qwen2.5-7B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen2.5-Coder-32B-Instruct": { - id: "Qwen/Qwen2.5-Coder-32B-Instruct", - name: "Qwen/Qwen2.5-Coder-32B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-11-11", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-VL-30B-A3B-Instruct": { - id: "Qwen/Qwen3-VL-30B-A3B-Instruct", - name: "Qwen/Qwen3-VL-30B-A3B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-05", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/QwQ-32B": { - id: "Qwen/QwQ-32B", - name: "Qwen/QwQ-32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-06", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.58 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-235B-A22B": { - id: "Qwen/Qwen3-235B-A22B", - name: "Qwen/Qwen3-235B-A22B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.35, output: 1.42 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Captioner": { - id: "Qwen/Qwen3-Omni-30B-A3B-Captioner", - name: "Qwen/Qwen3-Omni-30B-A3B-Captioner", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/Qwen3-VL-8B-Thinking": { - id: "Qwen/Qwen3-VL-8B-Thinking", - name: "Qwen/Qwen3-VL-8B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 2 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-VL-7B-Instruct": { - id: "Qwen/Qwen2.5-VL-7B-Instruct", - name: "Qwen/Qwen2.5-VL-7B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-28", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Instruct": { - id: "Qwen/Qwen3-Next-80B-A3B-Instruct", - name: "Qwen/Qwen3-Next-80B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 1.4 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-8B": { - id: "Qwen/Qwen3-8B", - name: "Qwen/Qwen3-8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.06 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen/Qwen3-30B-A3B-Instruct-2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.3 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen/Qwen3-235B-A22B-Instruct-2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-23", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-32B": { - id: "Qwen/Qwen3-32B", - name: "Qwen/Qwen3-32B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Coder-30B-A3B-Instruct": { - id: "Qwen/Qwen3-Coder-30B-A3B-Instruct", - name: "Qwen/Qwen3-Coder-30B-A3B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-01", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Instruct": { - id: "Qwen/Qwen3-Omni-30B-A3B-Instruct", - name: "Qwen/Qwen3-Omni-30B-A3B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/Qwen3-14B": { - id: "Qwen/Qwen3-14B", - name: "Qwen/Qwen3-14B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen2.5-72B-Instruct-128K": { - id: "Qwen/Qwen2.5-72B-Instruct-128K", - name: "Qwen/Qwen2.5-72B-Instruct-128K", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 131000, output: 4000 }, - }, - "Qwen/Qwen2.5-32B-Instruct": { - id: "Qwen/Qwen2.5-32B-Instruct", - name: "Qwen/Qwen2.5-32B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-19", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen/Qwen3-235B-A22B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-Omni-30B-A3B-Thinking": { - id: "Qwen/Qwen3-Omni-30B-A3B-Thinking", - name: "Qwen/Qwen3-Omni-30B-A3B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4 }, - limit: { context: 66000, output: 66000 }, - }, - "Qwen/Qwen2.5-VL-32B-Instruct": { - id: "Qwen/Qwen2.5-VL-32B-Instruct", - name: "Qwen/Qwen2.5-VL-32B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-24", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 131000, output: 131000 }, - }, - "Qwen/Qwen3-Next-80B-A3B-Thinking": { - id: "Qwen/Qwen3-Next-80B-A3B-Thinking", - name: "Qwen/Qwen3-Next-80B-A3B-Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-25", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Instruct": { - id: "Qwen/Qwen3-VL-235B-A22B-Instruct", - name: "Qwen/Qwen3-VL-235B-A22B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-14B-Instruct": { - id: "Qwen/Qwen2.5-14B-Instruct", - name: "Qwen/Qwen2.5-14B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 33000, output: 4000 }, - }, - "Qwen/Qwen3-VL-30B-A3B-Thinking": { - id: "Qwen/Qwen3-VL-30B-A3B-Thinking", - name: "Qwen/Qwen3-VL-30B-A3B-Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-11", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-32B-Instruct": { - id: "Qwen/Qwen3-VL-32B-Instruct", - name: "Qwen/Qwen3-VL-32B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-21", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-VL-8B-Instruct": { - id: "Qwen/Qwen3-VL-8B-Instruct", - name: "Qwen/Qwen3-VL-8B-Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.68 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - name: "Qwen/Qwen3-Coder-480B-A35B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 262000, output: 262000 }, - }, - "Qwen/Qwen2.5-72B-Instruct": { - id: "Qwen/Qwen2.5-72B-Instruct", - name: "Qwen/Qwen2.5-72B-Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.59, output: 0.59 }, - limit: { context: 33000, output: 4000 }, - }, - "stepfun-ai/Step-3.5-Flash": { - id: "stepfun-ai/Step-3.5-Flash", - name: "stepfun-ai/Step-3.5-Flash", - family: "step", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 262000, output: 262000 }, - }, - "zai-org/GLM-4.5": { - id: "zai-org/GLM-4.5", - name: "zai-org/GLM-4.5", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 131000, output: 131000 }, - }, - "zai-org/GLM-5V-Turbo": { - id: "zai-org/GLM-5V-Turbo", - name: "zai-org/GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "zai-org/GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 205000, output: 205000 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "zai-org/GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4, cache_write: 0 }, - limit: { context: 205000, output: 205000 }, - }, - "zai-org/GLM-4.5-Air": { - id: "zai-org/GLM-4.5-Air", - name: "zai-org/GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.86 }, - limit: { context: 131000, output: 131000 }, - }, - "zai-org/GLM-5": { - id: "zai-org/GLM-5", - name: "zai-org/GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2 }, - limit: { context: 205000, output: 205000 }, - }, - "zai-org/GLM-4.6V": { - id: "zai-org/GLM-4.6V", - name: "zai-org/GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-12-07", - last_updated: "2025-12-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 131000, output: 131000 }, - }, - "zai-org/GLM-4.6": { - id: "zai-org/GLM-4.6", - name: "zai-org/GLM-4.6", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-04", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.9 }, - limit: { context: 205000, output: 205000 }, - }, - "zai-org/GLM-4.5V": { - id: "zai-org/GLM-4.5V", - name: "zai-org/GLM-4.5V", - family: "glm", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.86 }, - limit: { context: 66000, output: 66000 }, - }, - "meta-llama/Meta-Llama-3.1-8B-Instruct": { - id: "meta-llama/Meta-Llama-3.1-8B-Instruct", - name: "meta-llama/Meta-Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-23", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.06 }, - limit: { context: 33000, output: 4000 }, - }, - "inclusionAI/Ring-flash-2.0": { - id: "inclusionAI/Ring-flash-2.0", - name: "inclusionAI/Ring-flash-2.0", - family: "ring", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "inclusionAI/Ling-mini-2.0": { - id: "inclusionAI/Ling-mini-2.0", - name: "inclusionAI/Ling-mini-2.0", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-10", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.28 }, - limit: { context: 131000, output: 131000 }, - }, - "inclusionAI/Ling-flash-2.0": { - id: "inclusionAI/Ling-flash-2.0", - name: "inclusionAI/Ling-flash-2.0", - family: "ling", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "tencent/Hunyuan-A13B-Instruct": { - id: "tencent/Hunyuan-A13B-Instruct", - name: "tencent/Hunyuan-A13B-Instruct", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-06-30", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "tencent/Hunyuan-MT-7B": { - id: "tencent/Hunyuan-MT-7B", - name: "tencent/Hunyuan-MT-7B", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 33000, output: 33000 }, - }, - "deepseek-ai/DeepSeek-V3.1": { - id: "deepseek-ai/DeepSeek-V3.1", - name: "deepseek-ai/DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-25", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/deepseek-vl2": { - id: "deepseek-ai/deepseek-vl2", - name: "deepseek-ai/deepseek-vl2", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-13", - last_updated: "2025-11-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 4000, output: 4000 }, - }, - "deepseek-ai/DeepSeek-V3": { - id: "deepseek-ai/DeepSeek-V3", - name: "deepseek-ai/DeepSeek-V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-12-26", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B": { - id: "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - name: "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0.18 }, - limit: { context: 131000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-R1": { - id: "deepseek-ai/DeepSeek-R1", - name: "deepseek-ai/DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.18 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B": { - id: "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", - name: "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-20", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131000, output: 131000 }, - }, - "deepseek-ai/DeepSeek-V3.2-Exp": { - id: "deepseek-ai/DeepSeek-V3.2-Exp", - name: "deepseek-ai/DeepSeek-V3.2-Exp", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-10", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.41 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-V3.2": { - id: "deepseek-ai/DeepSeek-V3.2", - name: "deepseek-ai/DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2025-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.42 }, - limit: { context: 164000, output: 164000 }, - }, - "deepseek-ai/DeepSeek-V3.1-Terminus": { - id: "deepseek-ai/DeepSeek-V3.1-Terminus", - name: "deepseek-ai/DeepSeek-V3.1-Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 1 }, - limit: { context: 164000, output: 164000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "openai/gpt-oss-20b", - family: "gpt-oss", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.18 }, - limit: { context: 131000, output: 8000 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "openai/gpt-oss-120b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.45 }, - limit: { context: 131000, output: 8000 }, - }, - "baidu/ERNIE-4.5-300B-A47B": { - id: "baidu/ERNIE-4.5-300B-A47B", - name: "baidu/ERNIE-4.5-300B-A47B", - family: "ernie", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-02", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 131000, output: 131000 }, - }, - "THUDM/GLM-Z1-9B-0414": { - id: "THUDM/GLM-Z1-9B-0414", - name: "THUDM/GLM-Z1-9B-0414", - family: "glm-z", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.086, output: 0.086 }, - limit: { context: 131000, output: 131000 }, - }, - "THUDM/GLM-4-9B-0414": { - id: "THUDM/GLM-4-9B-0414", - name: "THUDM/GLM-4-9B-0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.086, output: 0.086 }, - limit: { context: 33000, output: 33000 }, - }, - "THUDM/GLM-4-32B-0414": { - id: "THUDM/GLM-4-32B-0414", - name: "THUDM/GLM-4-32B-0414", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 33000, output: 33000 }, - }, - "THUDM/GLM-Z1-32B-0414": { - id: "THUDM/GLM-Z1-32B-0414", - name: "THUDM/GLM-Z1-32B-0414", - family: "glm-z", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-18", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.57 }, - limit: { context: 131000, output: 131000 }, - }, - "moonshotai/Kimi-K2-Thinking": { - id: "moonshotai/Kimi-K2-Thinking", - name: "moonshotai/Kimi-K2-Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-11-07", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.55, output: 2.5 }, - limit: { context: 262000, output: 262000 }, - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "moonshotai/Kimi-K2.6", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262000, output: 262000 }, - }, - "moonshotai/Kimi-K2-Instruct": { - id: "moonshotai/Kimi-K2-Instruct", - name: "moonshotai/Kimi-K2-Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-13", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.58, output: 2.29 }, - limit: { context: 131000, output: 131000 }, - }, - "moonshotai/Kimi-K2-Instruct-0905": { - id: "moonshotai/Kimi-K2-Instruct-0905", - name: "moonshotai/Kimi-K2-Instruct-0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-08", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 262000, output: 262000 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "moonshotai/Kimi-K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.25 }, - limit: { context: 262000, output: 262000 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMaxAI/MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 197000, output: 131000 }, - }, - "MiniMaxAI/MiniMax-M2.1": { - id: "MiniMaxAI/MiniMax-M2.1", - name: "MiniMaxAI/MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 197000, output: 131000 }, - }, - "ByteDance-Seed/Seed-OSS-36B-Instruct": { - id: "ByteDance-Seed/Seed-OSS-36B-Instruct", - name: "ByteDance-Seed/Seed-OSS-36B-Instruct", - family: "seed", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-04", - last_updated: "2025-11-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.57 }, - limit: { context: 262000, output: 262000 }, - }, - }, - }, - vercel: { - id: "vercel", - env: ["AI_GATEWAY_API_KEY"], - npm: "@ai-sdk/gateway", - name: "Vercel AI Gateway", - doc: "https://github.com/vercel/ai/tree/5eb85cc45a259553501f535b8ac79a77d0e79223/packages/gateway", - models: { - "alibaba/qwen3-coder-plus": { - id: "alibaba/qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 5 }, - limit: { context: 1000000, output: 1000000 }, - }, - "alibaba/qwen3.6-27b": { - id: "alibaba/qwen3.6-27b", - name: "Qwen 3.6 27B", - family: "qwen3.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 3.5999999999999996 }, - limit: { context: 256000, output: 256000 }, - }, - "alibaba/qwen3-embedding-8b": { - id: "alibaba/qwen3-embedding-8b", - name: "Qwen3 Embedding 8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0 }, - limit: { context: 32768, output: 32768 }, - }, - "alibaba/qwen-3-30b": { - id: "alibaba/qwen-3-30b", - name: "Qwen3-30B-A3B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.29 }, - limit: { context: 40960, output: 16384 }, - }, - "alibaba/qwen-3-235b": { - id: "alibaba/qwen-3-235b", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0.6 }, - limit: { context: 40960, output: 16384 }, - }, - "alibaba/qwen3.5-flash": { - id: "alibaba/qwen3.5-flash", - name: "Qwen 3.5 Flash", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.001, cache_write: 0.125 }, - limit: { context: 1000000, output: 64000 }, - }, - "alibaba/qwen3.6-plus": { - id: "alibaba/qwen3.6-plus", - name: "Qwen 3.6 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.09999999999999999, cache_write: 0.625 }, - limit: { context: 1000000, output: 64000 }, - }, - "alibaba/qwen3-max": { - id: "alibaba/qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6 }, - limit: { context: 262144, output: 32768 }, - }, - "alibaba/qwen3-embedding-0.6b": { - id: "alibaba/qwen3-embedding-0.6b", - name: "Qwen3 Embedding 0.6B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.01, output: 0 }, - limit: { context: 32768, output: 32768 }, - }, - "alibaba/qwen-3-32b": { - id: "alibaba/qwen-3-32b", - name: "Qwen 3.32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 40960, output: 16384 }, - }, - "alibaba/qwen-3.6-max-preview": { - id: "alibaba/qwen-3.6-max-preview", - name: "Qwen 3.6 Max Preview", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 1.3, output: 7.8, cache_read: 0.26, cache_write: 1.625 }, - limit: { context: 240000, output: 64000 }, - }, - "alibaba/qwen3-next-80b-a3b-thinking": { - id: "alibaba/qwen3-next-80b-a3b-thinking", - name: "Qwen3 Next 80B A3B Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-12", - last_updated: "2025-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 131072, output: 65536 }, - }, - "alibaba/qwen3-vl-thinking": { - id: "alibaba/qwen3-vl-thinking", - name: "Qwen3 VL Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 8.4 }, - limit: { context: 131072, output: 129024 }, - }, - "alibaba/qwen3-235b-a22b-thinking": { - id: "alibaba/qwen3-235b-a22b-thinking", - name: "Qwen3 235B A22B Thinking 2507", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.9 }, - limit: { context: 262114, output: 262114 }, - }, - "alibaba/qwen3-next-80b-a3b-instruct": { - id: "alibaba/qwen3-next-80b-a3b-instruct", - name: "Qwen3 Next 80B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-12", - last_updated: "2025-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 1.1 }, - limit: { context: 262144, output: 32768 }, - }, - "alibaba/qwen3-coder-next": { - id: "alibaba/qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-07-22", - last_updated: "2026-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.2 }, - limit: { context: 256000, output: 256000 }, - }, - "alibaba/qwen3-embedding-4b": { - id: "alibaba/qwen3-embedding-4b", - name: "Qwen3 Embedding 4B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 32768, output: 32768 }, - }, - "alibaba/qwen3-max-thinking": { - id: "alibaba/qwen3-max-thinking", - name: "Qwen 3 Max Thinking", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 6, cache_read: 0.24 }, - limit: { context: 256000, output: 65536 }, - }, - "alibaba/qwen3-vl-235b-a22b-instruct": { - id: "alibaba/qwen3-vl-235b-a22b-instruct", - name: "Qwen3 VL 235B A22B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-09-24", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39999999999999997, output: 1.5999999999999999 }, - limit: { context: 131072, output: 129024 }, - }, - "alibaba/qwen3-coder": { - id: "alibaba/qwen3-coder", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.38, output: 1.53 }, - limit: { context: 262144, output: 66536 }, - }, - "alibaba/qwen3-max-preview": { - id: "alibaba/qwen3-max-preview", - name: "Qwen3 Max Preview", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6, cache_read: 0.24 }, - limit: { context: 262144, output: 32768 }, - }, - "alibaba/qwen3.5-plus": { - id: "alibaba/qwen3.5-plus", - name: "Qwen 3.5 Plus", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-16", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2.4, cache_read: 0.04, cache_write: 0.5 }, - limit: { context: 1000000, output: 64000 }, - }, - "alibaba/qwen-3-14b": { - id: "alibaba/qwen-3-14b", - name: "Qwen3-14B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.24 }, - limit: { context: 40960, output: 16384 }, - }, - "alibaba/qwen3-vl-instruct": { - id: "alibaba/qwen3-vl-instruct", - name: "Qwen3 VL Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-24", - last_updated: "2025-09-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8 }, - limit: { context: 131072, output: 129024 }, - }, - "alibaba/qwen3-coder-30b-a3b": { - id: "alibaba/qwen3-coder-30b-a3b", - name: "Qwen 3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.27 }, - limit: { context: 160000, output: 32768 }, - }, - "perplexity/sonar-pro": { - id: "perplexity/sonar-pro", - name: "Sonar Pro", - family: "sonar-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8000 }, - }, - "perplexity/sonar": { - id: "perplexity/sonar", - name: "Sonar", - family: "sonar", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-02", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 127000, output: 8000 }, - }, - "perplexity/sonar-reasoning": { - id: "perplexity/sonar-reasoning", - name: "Sonar Reasoning", - family: "sonar-reasoning", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-09", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5 }, - limit: { context: 127000, output: 8000 }, - }, - "perplexity/sonar-reasoning-pro": { - id: "perplexity/sonar-reasoning-pro", - name: "Sonar Reasoning Pro", - family: "sonar-reasoning", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-09", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 127000, output: 8000 }, - }, - "deepseek/deepseek-v3.2-thinking": { - id: "deepseek/deepseek-v3.2-thinking", - name: "DeepSeek V3.2 Thinking", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.28, output: 0.42, cache_read: 0.03 }, - limit: { context: 128000, output: 64000 }, - }, - "deepseek/deepseek-v3.2-exp": { - id: "deepseek/deepseek-v3.2-exp", - name: "DeepSeek V3.2 Exp", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.4 }, - limit: { context: 163840, output: 163840 }, - }, - "deepseek/deepseek-v3.1": { - id: "deepseek/deepseek-v3.1", - name: "DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1 }, - limit: { context: 163840, output: 128000 }, - }, - "deepseek/deepseek-v4-flash": { - id: "deepseek/deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-23", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek/deepseek-v4-pro": { - id: "deepseek/deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-23", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - }, - "deepseek/deepseek-v3.2": { - id: "deepseek/deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.27, output: 0.4, cache_read: 0.22 }, - limit: { context: 163842, output: 8000 }, - }, - "deepseek/deepseek-v3": { - id: "deepseek/deepseek-v3", - name: "DeepSeek V3 0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-12-26", - last_updated: "2024-12-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.77, output: 0.77 }, - limit: { context: 163840, output: 16384 }, - }, - "deepseek/deepseek-v3.1-terminus": { - id: "deepseek/deepseek-v3.1-terminus", - name: "DeepSeek V3.1 Terminus", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-22", - last_updated: "2025-09-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1 }, - limit: { context: 131072, output: 65536 }, - }, - "deepseek/deepseek-r1": { - id: "deepseek/deepseek-r1", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 128000, output: 32768 }, - }, - "arcee-ai/trinity-mini": { - id: "arcee-ai/trinity-mini", - name: "Trinity Mini", - family: "trinity", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12", - last_updated: "2025-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.15 }, - limit: { context: 131072, output: 131072 }, - }, - "arcee-ai/trinity-large-thinking": { - id: "arcee-ai/trinity-large-thinking", - name: "Trinity Large Thinking", - family: "trinity", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 0.8999999999999999 }, - limit: { context: 262100, output: 80000 }, - }, - "arcee-ai/trinity-large-preview": { - id: "arcee-ai/trinity-large-preview", - name: "Trinity Large Preview", - family: "trinity", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 131000, output: 131000 }, - }, - "recraft/recraft-v3": { - id: "recraft/recraft-v3", - name: "Recraft V3", - family: "recraft", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-10", - last_updated: "2024-10", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "recraft/recraft-v2": { - id: "recraft/recraft-v2", - name: "Recraft V2", - family: "recraft", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03", - last_updated: "2024-03", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "voyage/voyage-3-large": { - id: "voyage/voyage-3-large", - name: "voyage-3-large", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-4-large": { - id: "voyage/voyage-4-large", - name: "voyage-4-large", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-06", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 32000, output: 0 }, - }, - "voyage/voyage-3.5-lite": { - id: "voyage/voyage-3.5-lite", - name: "voyage-3.5-lite", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-code-3": { - id: "voyage/voyage-code-3", - name: "voyage-code-3", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.18, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-finance-2": { - id: "voyage/voyage-finance-2", - name: "voyage-finance-2", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03", - last_updated: "2024-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-4-lite": { - id: "voyage/voyage-4-lite", - name: "voyage-4-lite", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-06", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 32000, output: 0 }, - }, - "voyage/voyage-4": { - id: "voyage/voyage-4", - name: "voyage-4", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-06", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 32000, output: 0 }, - }, - "voyage/voyage-code-2": { - id: "voyage/voyage-code-2", - name: "voyage-code-2", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-01", - last_updated: "2024-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-law-2": { - id: "voyage/voyage-law-2", - name: "voyage-law-2", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03", - last_updated: "2024-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "voyage/voyage-3.5": { - id: "voyage/voyage-3.5", - name: "voyage-3.5", - family: "voyage", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "morph/morph-v3-large": { - id: "morph/morph-v3-large", - name: "Morph v3 Large", - family: "morph", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.9, output: 1.9 }, - limit: { context: 32000, output: 32000 }, - }, - "morph/morph-v3-fast": { - id: "morph/morph-v3-fast", - name: "Morph v3 Fast", - family: "morph", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08-15", - last_updated: "2024-08-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 1.2 }, - limit: { context: 16000, output: 16000 }, - }, - "zai/glm-5v-turbo": { - id: "zai/glm-5v-turbo", - name: "GLM 5V Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4, cache_read: 0.24 }, - limit: { context: 200000, output: 128000 }, - }, - "zai/glm-4.7": { - id: "zai/glm-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.43, output: 1.75, cache_read: 0.08 }, - limit: { context: 202752, output: 120000 }, - }, - "zai/glm-5": { - id: "zai/glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2 }, - limit: { context: 202800, output: 131072 }, - }, - "zai/glm-4.7-flashx": { - id: "zai/glm-4.7-flashx", - name: "GLM 4.7 FlashX", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4, cache_read: 0.01 }, - limit: { context: 200000, output: 128000 }, - }, - "zai/glm-5.1": { - id: "zai/glm-5.1", - name: "GLM 5.1", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.4, output: 4.4, cache_read: 0.26 }, - limit: { context: 202752, output: 202752 }, - }, - "zai/glm-4.6v-flash": { - id: "zai/glm-4.6v-flash", - name: "GLM-4.6V-Flash", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 24000 }, - }, - "zai/glm-4.5": { - id: "zai/glm-4.5", - name: "GLM 4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 131072, output: 131072 }, - }, - "zai/glm-4.5-air": { - id: "zai/glm-4.5-air", - name: "GLM 4.5 Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 128000, output: 96000 }, - }, - "zai/glm-5-turbo": { - id: "zai/glm-5-turbo", - name: "GLM 5 Turbo", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 4, cache_read: 0.24 }, - limit: { context: 202800, output: 131100 }, - }, - "zai/glm-4.5v": { - id: "zai/glm-4.5v", - name: "GLM 4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 66000, output: 66000 }, - }, - "zai/glm-4.6": { - id: "zai/glm-4.6", - name: "GLM 4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 1.8 }, - limit: { context: 200000, output: 96000 }, - }, - "zai/glm-4.6v": { - id: "zai/glm-4.6v", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9, cache_read: 0.05 }, - limit: { context: 128000, output: 24000 }, - }, - "zai/glm-4.7-flash": { - id: "zai/glm-4.7-flash", - name: "GLM 4.7 Flash", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-13", - last_updated: "2026-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.39999999999999997 }, - limit: { context: 200000, output: 131000 }, - }, - "cohere/command-a": { - id: "cohere/command-a", - name: "Command A", - family: "command", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 8000 }, - }, - "cohere/embed-v4.0": { - id: "cohere/embed-v4.0", - name: "Embed v4.0", - family: "cohere-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.12, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "prime-intellect/intellect-3": { - id: "prime-intellect/intellect-3", - name: "INTELLECT 3", - family: "intellect", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-11-26", - last_updated: "2025-11-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 131072, output: 131072 }, - }, - "xai/grok-4.3": { - id: "xai/grok-4.3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-30", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 2.5, cache_read: 0.19999999999999998 }, - limit: { context: 1000000, output: 1000000 }, - }, - "xai/grok-4.20-non-reasoning": { - id: "xai/grok-4.20-non-reasoning", - name: "Grok 4.20 Non-Reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-4.20-non-reasoning-beta": { - id: "xai/grok-4.20-non-reasoning-beta", - name: "Grok 4.20 Beta Non-Reasoning", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-4.20-reasoning": { - id: "xai/grok-4.20-reasoning", - name: "Grok 4.20 Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-imagine-image": { - id: "xai/grok-imagine-image", - name: "Grok Imagine Image", - family: "grok", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-28", - last_updated: "2026-02-19", - modalities: { input: ["text"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "xai/grok-4.20-multi-agent-beta": { - id: "xai/grok-4.20-multi-agent-beta", - name: "Grok 4.20 Multi Agent Beta", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-imagine-image-pro": { - id: "xai/grok-imagine-image-pro", - name: "Grok Imagine Image Pro", - family: "grok", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-01-28", - last_updated: "2026-02-19", - modalities: { input: ["text"], output: ["text", "image"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "xai/grok-4-fast-reasoning": { - id: "xai/grok-4-fast-reasoning", - name: "Grok 4 Fast Reasoning", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 256000 }, - }, - "xai/grok-4.1-fast-non-reasoning": { - id: "xai/grok-4.1-fast-non-reasoning", - name: "Grok 4.1 Fast Non-Reasoning", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "xai/grok-4.20-reasoning-beta": { - id: "xai/grok-4.20-reasoning-beta", - name: "Grok 4.20 Beta Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-4.20-multi-agent": { - id: "xai/grok-4.20-multi-agent", - name: "Grok 4.20 Multi-Agent", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.19999999999999998 }, - limit: { context: 2000000, output: 2000000 }, - }, - "xai/grok-4.1-fast-reasoning": { - id: "xai/grok-4.1-fast-reasoning", - name: "Grok 4.1 Fast Reasoning", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "xai/grok-4-fast-non-reasoning": { - id: "xai/grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "xai/grok-3": { - id: "xai/grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "xai/grok-3-mini": { - id: "xai/grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, reasoning: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - "xai/grok-2-vision": { - id: "xai/grok-2-vision", - name: "Grok 2 Vision", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 10, cache_read: 2 }, - limit: { context: 8192, output: 4096 }, - }, - "xai/grok-4": { - id: "xai/grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, reasoning: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "xai/grok-code-fast-1": { - id: "xai/grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "xai/grok-3-fast": { - id: "xai/grok-3-fast", - name: "Grok 3 Fast", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 1.25 }, - limit: { context: 131072, output: 8192 }, - }, - "xai/grok-3-mini-fast": { - id: "xai/grok-3-mini-fast", - name: "Grok 3 Mini Fast", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 4, reasoning: 4, cache_read: 0.15 }, - limit: { context: 131072, output: 8192 }, - }, - "nvidia/nemotron-3-super-120b-a12b": { - id: "nvidia/nemotron-3-super-120b-a12b", - name: "NVIDIA Nemotron 3 Super 120B A12B", - family: "nemotron", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.65 }, - limit: { context: 256000, output: 32000 }, - }, - "nvidia/nemotron-3-nano-30b-a3b": { - id: "nvidia/nemotron-3-nano-30b-a3b", - name: "Nemotron 3 Nano 30B A3B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.24 }, - limit: { context: 262144, output: 262144 }, - }, - "nvidia/nemotron-nano-12b-v2-vl": { - id: "nvidia/nemotron-nano-12b-v2-vl", - name: "Nvidia Nemotron Nano 12B V2 VL", - family: "nemotron", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12", - last_updated: "2024-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 131072, output: 131072 }, - }, - "nvidia/nemotron-nano-9b-v2": { - id: "nvidia/nemotron-nano-9b-v2", - name: "Nvidia Nemotron Nano 9B V2", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-18", - last_updated: "2025-08-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.16 }, - limit: { context: 131072, output: 131072 }, - }, - "inception/mercury-edit-2": { - id: "inception/mercury-edit-2", - name: "Mercury Edit 2", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-30", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.025 }, - limit: { context: 128000, output: 8192 }, - }, - "inception/mercury-2": { - id: "inception/mercury-2", - name: "Mercury 2", - family: "mercury", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-03-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 0.75, cache_read: 0.024999999999999998 }, - limit: { context: 128000, output: 128000 }, - }, - "inception/mercury-coder-small": { - id: "inception/mercury-coder-small", - name: "Mercury Coder Small Beta", - family: "mercury", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-02-26", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1 }, - limit: { context: 32000, output: 16384 }, - }, - "openai/gpt-5.1-codex-max": { - id: "openai/gpt-5.1-codex-max", - name: "GPT 5.1 Codex Max", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.2-chat": { - id: "openai/gpt-5.2-chat", - name: "GPT-5.2 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.18 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "openai/gpt-4o-mini-search-preview": { - id: "openai/gpt-4o-mini-search-preview", - name: "GPT 4o Mini Search Preview", - family: "gpt-mini", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2023-09", - release_date: "2025-01", - last_updated: "2025-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "openai/codex-mini": { - id: "openai/codex-mini", - name: "Codex Mini", - family: "gpt-codex-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-16", - last_updated: "2025-05-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 6, cache_read: 0.38 }, - limit: { context: 200000, input: 100000, output: 100000 }, - }, - "openai/gpt-5-chat": { - id: "openai/gpt-5-chat", - name: "GPT-5 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "openai/gpt-5.3-chat": { - id: "openai/gpt-5.3-chat", - name: "GPT-5.3 Chat", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-03", - last_updated: "2026-03-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "openai/gpt-5.2-pro": { - id: "openai/gpt-5.2-pro", - name: "GPT 5.2 ", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/text-embedding-3-large": { - id: "openai/text-embedding-3-large", - name: "text-embedding-3-large", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0 }, - limit: { context: 8192, input: 6656, output: 1536 }, - }, - "openai/gpt-5.5": { - id: "openai/gpt-5.5", - name: "GPT 5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5 }, - limit: { context: 1000000, input: 872000, output: 128000 }, - }, - "openai/gpt-5.3-codex": { - id: "openai/gpt-5.3-codex", - name: "GPT 5.3 Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/text-embedding-ada-002": { - id: "openai/text-embedding-ada-002", - name: "text-embedding-ada-002", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2022-12-15", - last_updated: "2022-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8192, input: 6656, output: 1536 }, - }, - "openai/gpt-5.2": { - id: "openai/gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.18 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/o3-pro": { - id: "openai/o3-pro", - name: "o3 Pro", - family: "o-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-10", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 20, output: 80 }, - limit: { context: 200000, input: 100000, output: 100000 }, - }, - "openai/gpt-5.4-mini": { - id: "openai/gpt-5.4-mini", - name: "GPT 5.4 Mini", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.4-nano": { - id: "openai/gpt-5.4-nano", - name: "GPT 5.4 Nano", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.19999999999999998, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.2-codex": { - id: "openai/gpt-5.2-codex", - name: "GPT-5.2-Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12", - last_updated: "2025-12", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.1-codex-mini": { - id: "openai/gpt-5.1-codex-mini", - name: "GPT-5.1 Codex mini", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-16", - last_updated: "2025-05-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.1-thinking": { - id: "openai/gpt-5.1-thinking", - name: "GPT 5.1 Thinking", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5.4-pro": { - id: "openai/gpt-5.4-pro", - name: "GPT 5.4 Pro", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-05", - last_updated: "2026-03-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-3.5-turbo": { - id: "openai/gpt-3.5-turbo", - name: "GPT-3.5 Turbo", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-09", - release_date: "2023-03-01", - last_updated: "2023-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 16385, input: 12289, output: 4096 }, - }, - "openai/o3-deep-research": { - id: "openai/o3-deep-research", - name: "o3-deep-research", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-10", - release_date: "2024-06-26", - last_updated: "2024-06-26", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 40, cache_read: 2.5 }, - limit: { context: 200000, input: 100000, output: 100000 }, - }, - "openai/text-embedding-3-small": { - id: "openai/text-embedding-3-small", - name: "text-embedding-3-small", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8192, input: 6656, output: 1536 }, - }, - "openai/gpt-5.4": { - id: "openai/gpt-5.4", - name: "GPT 5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-05", - last_updated: "2026-03-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.3 }, - limit: { context: 131072, input: 98304, output: 32768 }, - }, - "openai/gpt-5-pro": { - id: "openai/gpt-5-pro", - name: "GPT-5 pro", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, input: 128000, output: 272000 }, - }, - "openai/gpt-oss-safeguard-20b": { - id: "openai/gpt-oss-safeguard-20b", - name: "gpt-oss-safeguard-20b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.08, output: 0.3, cache_read: 0.04 }, - limit: { context: 131072, input: 65536, output: 65536 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 131072, output: 131072 }, - }, - "openai/gpt-5.5-pro": { - id: "openai/gpt-5.5-pro", - name: "GPT 5.5 Pro", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 1000000, input: 872000, output: 128000 }, - }, - "openai/gpt-3.5-turbo-instruct": { - id: "openai/gpt-3.5-turbo-instruct", - name: "GPT-3.5 Turbo Instruct", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-09", - release_date: "2023-03-01", - last_updated: "2023-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 8192, input: 4096, output: 4096 }, - }, - "openai/gpt-5.1-instant": { - id: "openai/gpt-5.1-instant", - name: "GPT-5.1 Instant", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 128000, input: 111616, output: 16384 }, - }, - "openai/gpt-5.1-codex": { - id: "openai/gpt-5.1-codex", - name: "GPT-5.1-Codex", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o3": { - id: "openai/o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4.1-nano": { - id: "openai/gpt-4.1-nano", - name: "GPT-4.1 nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03 }, - limit: { context: 1047576, output: 32768 }, - }, - "openai/gpt-5-codex": { - id: "openai/gpt-5-codex", - name: "GPT-5-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o1": { - id: "openai/o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4-turbo": { - id: "openai/gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "amazon/titan-embed-text-v2": { - id: "amazon/titan-embed-text-v2", - name: "Titan Text Embeddings V2", - family: "titan-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-04", - last_updated: "2024-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "amazon/nova-2-lite": { - id: "amazon/nova-2-lite", - name: "Nova 2 Lite", - family: "nova", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-01", - last_updated: "2024-12-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 1000000, output: 1000000 }, - }, - "amazon/nova-pro": { - id: "amazon/nova-pro", - name: "Nova Pro", - family: "nova-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2, cache_read: 0.2 }, - limit: { context: 300000, output: 8192 }, - }, - "amazon/nova-lite": { - id: "amazon/nova-lite", - name: "Nova Lite", - family: "nova-lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.06, output: 0.24, cache_read: 0.015 }, - limit: { context: 300000, output: 8192 }, - }, - "amazon/nova-micro": { - id: "amazon/nova-micro", - name: "Nova Micro", - family: "nova-micro", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-03", - last_updated: "2024-12-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.035, output: 0.14, cache_read: 0.00875 }, - limit: { context: 128000, output: 8192 }, - }, - "mistral/mistral-nemo": { - id: "mistral/mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.17 }, - limit: { context: 60288, output: 16000 }, - }, - "mistral/ministral-14b": { - id: "mistral/ministral-14b", - name: "Ministral 14B", - family: "ministral", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 256000, output: 256000 }, - }, - "mistral/codestral-embed": { - id: "mistral/codestral-embed", - name: "Codestral Embed", - family: "codestral-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "mistral/mistral-medium": { - id: "mistral/mistral-medium", - name: "Mistral Medium 3.1", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 128000, output: 64000 }, - }, - "mistral/mistral-embed": { - id: "mistral/mistral-embed", - name: "Mistral Embed", - family: "mistral-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-12-11", - last_updated: "2023-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "mistral/devstral-2": { - id: "mistral/devstral-2", - name: "Devstral 2", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 256000 }, - }, - "mistral/mistral-large-3": { - id: "mistral/mistral-large-3", - name: "Mistral Large 3", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 256000, output: 256000 }, - }, - "mistral/devstral-small-2": { - id: "mistral/devstral-small-2", - name: "Devstral Small 2", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 256000 }, - }, - "mistral/devstral-small": { - id: "mistral/devstral-small", - name: "Devstral Small 1.1", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 64000 }, - }, - "mistral/ministral-8b": { - id: "mistral/ministral-8b", - name: "Ministral 8B (latest)", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral/magistral-medium": { - id: "mistral/magistral-medium", - name: "Magistral Medium (latest)", - family: "magistral-medium", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-03-17", - last_updated: "2025-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 5 }, - limit: { context: 128000, output: 16384 }, - }, - "mistral/mistral-small": { - id: "mistral/mistral-small", - name: "Mistral Small (latest)", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2026-03-16", - last_updated: "2026-03-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 256000, output: 256000 }, - }, - "mistral/magistral-small": { - id: "mistral/magistral-small", - name: "Magistral Small", - family: "magistral-small", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-06", - release_date: "2025-03-17", - last_updated: "2025-03-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral/pixtral-12b": { - id: "mistral/pixtral-12b", - name: "Pixtral 12B", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-09-01", - last_updated: "2024-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral/mixtral-8x22b-instruct": { - id: "mistral/mixtral-8x22b-instruct", - name: "Mixtral 8x22B", - family: "mixtral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-17", - last_updated: "2024-04-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 64000, output: 64000 }, - }, - "mistral/pixtral-large": { - id: "mistral/pixtral-large", - name: "Pixtral Large (latest)", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2024-11-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral/ministral-3b": { - id: "mistral/ministral-3b", - name: "Ministral 3B (latest)", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 128000, output: 128000 }, - }, - "mistral/codestral": { - id: "mistral/codestral", - name: "Codestral (latest)", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-05-29", - last_updated: "2025-01-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 4096 }, - }, - "meta/llama-3.2-1b": { - id: "meta/llama-3.2-1b", - name: "Llama 3.2 1B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/llama-3.1-8b": { - id: "meta/llama-3.1-8b", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0.05 }, - limit: { context: 131072, output: 16384 }, - }, - "meta/llama-3.2-90b": { - id: "meta/llama-3.2-90b", - name: "Llama 3.2 90B Vision Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/llama-3.2-3b": { - id: "meta/llama-3.2-3b", - name: "Llama 3.2 3B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/llama-3.2-11b": { - id: "meta/llama-3.2-11b", - name: "Llama 3.2 11B Vision Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.16, output: 0.16 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/llama-3.1-70b": { - id: "meta/llama-3.1-70b", - name: "Llama 3.1 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 0.4 }, - limit: { context: 131072, output: 16384 }, - }, - "meta/llama-3.3-70b": { - id: "meta/llama-3.3-70b", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-4-maverick": { - id: "meta/llama-4-maverick", - name: "Llama-4-Maverick-17B-128E-Instruct-FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "meta/llama-4-scout": { - id: "meta/llama-4-scout", - name: "Llama-4-Scout-17B-16E-Instruct-FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "vercel/v0-1.5-md": { - id: "vercel/v0-1.5-md", - name: "v0-1.5-md", - family: "v0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-09", - last_updated: "2025-06-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, output: 32000 }, - }, - "vercel/v0-1.0-md": { - id: "vercel/v0-1.0-md", - name: "v0-1.0-md", - family: "v0", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 128000, output: 32000 }, - }, - "minimax/minimax-m2.7": { - id: "minimax/minimax-m2.7", - name: "Minimax M2.7", - family: "minimax", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131000 }, - }, - "minimax/minimax-m2.7-highspeed": { - id: "minimax/minimax-m2.7-highspeed", - name: "MiniMax M2.7 High Speed", - family: "minimax", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131100 }, - }, - "minimax/minimax-m2": { - id: "minimax/minimax-m2", - name: "MiniMax M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 1.15, cache_read: 0.03, cache_write: 0.38 }, - limit: { context: 262114, output: 262114 }, - }, - "minimax/minimax-m2.1": { - id: "minimax/minimax-m2.1", - name: "MiniMax M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.38 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2.1-lightning": { - id: "minimax/minimax-m2.1-lightning", - name: "MiniMax M2.1 Lightning", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.4, cache_read: 0.03, cache_write: 0.38 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131000 }, - }, - "minimax/minimax-m2.5-highspeed": { - id: "minimax/minimax-m2.5-highspeed", - name: "MiniMax M2.5 High Speed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.4, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 0, output: 0 }, - }, - "kwaipilot/kat-coder-pro-v1": { - id: "kwaipilot/kat-coder-pro-v1", - name: "KAT-Coder-Pro V1", - family: "kat-coder", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-10-24", - last_updated: "2025-10-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 256000, output: 32000 }, - }, - "kwaipilot/kat-coder-pro-v2": { - id: "kwaipilot/kat-coder-pro-v2", - name: "Kat Coder Pro V2", - family: "kat-coder", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 256000, output: 256000 }, - }, - "google/gemini-2.5-flash-lite-preview-09-2025": { - id: "google/gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview 09-25", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.01 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-3.1-flash-lite-preview": { - id: "google/gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-03", - last_updated: "2026-03-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1000000, output: 65000 }, - }, - "google/gemini-3-pro-image": { - id: "google/gemini-3-pro-image", - name: "Nano Banana Pro (Gemini 3 Pro Image)", - family: "gemini-pro", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-03", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 2, output: 120 }, - limit: { context: 65536, output: 32768 }, - }, - "google/gemini-3.1-pro-preview": { - id: "google/gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-19", - last_updated: "2026-02-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 1000000, output: 64000 }, - }, - "google/gemini-3-pro-preview": { - id: "google/gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1000000, output: 64000 }, - }, - "google/imagen-4.0-ultra-generate-001": { - id: "google/imagen-4.0-ultra-generate-001", - name: "Imagen 4 Ultra", - family: "imagen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-24", - last_updated: "2025-05-24", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-embedding-001": { - id: "google/gemini-embedding-001", - name: "Gemini Embedding 001", - family: "gemini-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "google/gemma-4-31b-it": { - id: "google/gemma-4-31b-it", - name: "Gemma 4 31B IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.39999999999999997 }, - limit: { context: 262144, output: 131072 }, - }, - "google/gemini-2.5-flash-image": { - id: "google/gemini-2.5-flash-image", - name: "Nano Banana (Gemini 2.5 Flash Image)", - family: "gemini-flash", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-03-20", - modalities: { input: ["text"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 32768, output: 32768 }, - }, - "google/text-embedding-005": { - id: "google/text-embedding-005", - name: "Text Embedding 005", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-08", - last_updated: "2024-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "google/text-multilingual-embedding-002": { - id: "google/text-multilingual-embedding-002", - name: "Text Multilingual Embedding 002", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-03", - last_updated: "2024-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.03, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "google/gemini-3.1-flash-image-preview": { - id: "google/gemini-3.1-flash-image-preview", - name: "Gemini 3.1 Flash Image Preview (Nano Banana 2)", - family: "gemini", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-02-26", - last_updated: "2026-03-06", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.5, output: 3 }, - limit: { context: 131072, output: 32768 }, - }, - "google/gemini-3.1-flash-lite": { - id: "google/gemini-3.1-flash-lite", - name: "Gemini 3.1 Flash Lite", - family: "gemini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-05-07", - last_updated: "2026-05-08", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.03 }, - limit: { context: 1000000, output: 65000 }, - }, - "google/gemini-3-flash": { - id: "google/gemini-3-flash", - name: "Gemini 3 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 3, cache_read: 0.05 }, - limit: { context: 1000000, output: 64000 }, - }, - "google/imagen-4.0-generate-001": { - id: "google/imagen-4.0-generate-001", - name: "Imagen 4", - family: "imagen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-2.5-flash-preview-09-2025": { - id: "google/gemini-2.5-flash-preview-09-2025", - name: "Gemini 2.5 Flash Preview 09-25", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03, cache_write: 0.383 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-embedding-2": { - id: "google/gemini-embedding-2", - name: "Gemini Embedding 2", - family: "gemini-embedding", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-10", - last_updated: "2026-03-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 0, output: 0 }, - }, - "google/gemma-4-26b-a4b-it": { - id: "google/gemma-4-26b-a4b-it", - name: "Gemma 4 26B A4B IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-03", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0.39999999999999997 }, - limit: { context: 262144, output: 131072 }, - }, - "google/imagen-4.0-fast-generate-001": { - id: "google/imagen-4.0-fast-generate-001", - name: "Imagen 4 Fast", - family: "imagen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06", - last_updated: "2025-06", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 480, output: 0 }, - }, - "google/gemini-2.5-flash-lite": { - id: "google/gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.01 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-flash-image-preview": { - id: "google/gemini-2.5-flash-image-preview", - name: "Nano Banana Preview (Gemini 2.5 Flash Image Preview)", - family: "gemini-flash", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-03-20", - modalities: { input: ["text"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5 }, - limit: { context: 32768, output: 32768 }, - }, - "google/gemini-2.0-flash-lite": { - id: "google/gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 1048576, output: 8192 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.0-flash": { - id: "google/gemini-2.0-flash", - name: "Gemini 2.0 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 8192 }, - }, - "moonshotai/kimi-k2-turbo": { - id: "moonshotai/kimi-k2-turbo", - name: "Kimi K2 Turbo", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.4, output: 10 }, - limit: { context: 256000, output: 16384 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-26", - last_updated: "2026-01-26", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.2 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/kimi-k2-thinking-turbo": { - id: "moonshotai/kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.15, output: 8, cache_read: 0.15 }, - limit: { context: 262114, output: 262114 }, - }, - "moonshotai/kimi-k2-0905": { - id: "moonshotai/kimi-k2-0905", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 131072, output: 16384 }, - }, - "moonshotai/kimi-k2.6": { - id: "moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262000, output: 262000 }, - }, - "moonshotai/kimi-k2-thinking": { - id: "moonshotai/kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.47, output: 2, cache_read: 0.14 }, - limit: { context: 216144, output: 216144 }, - }, - "moonshotai/kimi-k2": { - id: "moonshotai/kimi-k2", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-14", - last_updated: "2025-07-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 131072, output: 16384 }, - status: "deprecated", - }, - "interfaze/interfaze-beta": { - id: "interfaze/interfaze-beta", - name: "Interfaze Beta", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2025-10-07", - last_updated: "2026-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 3.5 }, - limit: { context: 1000000, output: 32000 }, - }, - "anthropic/claude-3.5-sonnet-20240620": { - id: "anthropic/claude-3.5-sonnet-20240620", - name: "Claude 3.5 Sonnet (2024-06-20)", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-06-20", - last_updated: "2024-06-20", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-opus-4.6": { - id: "anthropic/claude-opus-4.6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02", - last_updated: "2026-02", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.7": { - id: "anthropic/claude-opus-4.7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-opus-4.5": { - id: "anthropic/claude-opus-4.5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 18.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4.6": { - id: "anthropic/claude-sonnet-4.6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 1000000, output: 128000 }, - }, - "anthropic/claude-3-opus": { - id: "anthropic/claude-3-opus", - name: "Claude Opus 3", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-02-29", - last_updated: "2024-02-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic/claude-3.5-haiku": { - id: "anthropic/claude-3.5-haiku", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-opus-4": { - id: "anthropic/claude-opus-4", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-3-haiku": { - id: "anthropic/claude-3-haiku", - name: "Claude Haiku 3", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-13", - last_updated: "2024-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "anthropic/claude-sonnet-4.5": { - id: "anthropic/claude-sonnet-4.5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-3.5-sonnet": { - id: "anthropic/claude-3.5-sonnet", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "anthropic/claude-3.7-sonnet": { - id: "anthropic/claude-3.7-sonnet", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "xiaomi/mimo-v2.5-pro": { - id: "xiaomi/mimo-v2.5-pro", - name: "MiMo V2.5 Pro", - family: "mimo-v2.5-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-05-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.19999999999999998 }, - limit: { context: 1050000, output: 131000 }, - }, - "xiaomi/mimo-v2.5": { - id: "xiaomi/mimo-v2.5", - name: "MiMo M2.5", - family: "mimo-v2.5", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-22", - last_updated: "2026-05-01", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.39999999999999997, output: 2, cache_read: 0.08 }, - limit: { context: 1050000, output: 131100 }, - }, - "xiaomi/mimo-v2-pro": { - id: "xiaomi/mimo-v2-pro", - name: "MiMo V2 Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.19999999999999998 }, - limit: { context: 1000000, output: 128000 }, - }, - "xiaomi/mimo-v2-flash": { - id: "xiaomi/mimo-v2-flash", - name: "MiMo V2 Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.29 }, - limit: { context: 262144, output: 32000 }, - }, - "bytedance/seed-1.6": { - id: "bytedance/seed-1.6", - name: "Seed 1.6", - family: "seed", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.05 }, - limit: { context: 256000, output: 32000 }, - }, - "bytedance/seed-1.8": { - id: "bytedance/seed-1.8", - name: "Seed 1.8", - family: "seed", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-10", - last_updated: "2025-10", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.05 }, - limit: { context: 256000, output: 64000 }, - }, - "meituan/longcat-flash-chat": { - id: "meituan/longcat-flash-chat", - name: "LongCat Flash Chat", - family: "longcat", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-08-30", - last_updated: "2025-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 128000, output: 8192 }, - }, - "meituan/longcat-flash-thinking": { - id: "meituan/longcat-flash-thinking", - name: "LongCat Flash Thinking", - family: "longcat", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 1.5 }, - limit: { context: 128000, output: 8192 }, - }, - "meituan/longcat-flash-thinking-2601": { - id: "meituan/longcat-flash-thinking-2601", - name: "LongCat Flash Thinking 2601", - family: "longcat", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - release_date: "2026-03-13", - last_updated: "2026-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - limit: { context: 32768, output: 32768 }, - }, - "bfl/flux-pro-1.0-fill": { - id: "bfl/flux-pro-1.0-fill", - name: "FLUX.1 Fill [pro]", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-10", - last_updated: "2024-10", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "bfl/flux-pro-1.1": { - id: "bfl/flux-pro-1.1", - name: "FLUX1.1 [pro]", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-10", - last_updated: "2024-10", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "bfl/flux-kontext-pro": { - id: "bfl/flux-kontext-pro", - name: "FLUX.1 Kontext Pro", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06", - last_updated: "2025-06", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "bfl/flux-kontext-max": { - id: "bfl/flux-kontext-max", - name: "FLUX.1 Kontext Max", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-06", - last_updated: "2025-06", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - "bfl/flux-pro-1.1-ultra": { - id: "bfl/flux-pro-1.1-ultra", - name: "FLUX1.1 [pro] Ultra", - family: "flux", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2024-11", - last_updated: "2024-11", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - limit: { context: 512, output: 0 }, - }, - }, - }, - minimax: { - id: "minimax", - env: ["MINIMAX_API_KEY"], - npm: "@ai-sdk/anthropic", - api: "https://api.minimax.io/anthropic/v1", - name: "MiniMax (minimax.io)", - doc: "https://platform.minimax.io/docs/guides/quickstart", - models: { - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196608, output: 128000 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7-highspeed": { - id: "MiniMax-M2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.5-highspeed": { - id: "MiniMax-M2.5-highspeed", - name: "MiniMax-M2.5-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - llmgateway: { - id: "llmgateway", - env: ["LLMGATEWAY_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.llmgateway.io/v1", - name: "LLM Gateway", - doc: "https://llmgateway.io/docs", - models: { - "gpt-4o-mini-search-preview": { - id: "gpt-4o-mini-search-preview", - name: "GPT-4o Mini Search Preview", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 16384 }, - }, - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "Grok 4.1 Fast Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "qwen3-235b-a22b-instruct-2507": { - id: "qwen3-235b-a22b-instruct-2507", - name: "Qwen3 235B A22B Instruct (2507)", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "llama-4-scout": { - id: "llama-4-scout", - name: "Llama 4 Scout", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.18, output: 0.59 }, - limit: { context: 32768, output: 16384 }, - status: "beta", - }, - "hermes-2-pro-llama-3-8b": { - id: "hermes-2-pro-llama-3-8b", - name: "Hermes 2 Pro Llama 3 8B", - family: "hermes", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-05-27", - last_updated: "2024-05-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.14 }, - limit: { context: 8192, output: 8192 }, - }, - "qwen-coder-plus": { - id: "qwen-coder-plus", - name: "Qwen Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1 }, - limit: { context: 131072, output: 8192 }, - }, - auto: { - id: "auto", - name: "Auto Route", - family: "auto", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-01-01", - last_updated: "2024-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "glm-4.6v-flashx": { - id: "glm-4.6v-flashx", - name: "GLM-4.6V FlashX", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.4, cache_read: 0 }, - limit: { context: 128000, output: 16000 }, - }, - "gemma-2-27b-it-together": { - id: "gemma-2-27b-it-together", - name: "Gemma 2 27B IT", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-06-27", - last_updated: "2024-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.08 }, - limit: { context: 8192, output: 16384 }, - }, - "codestral-2508": { - id: "codestral-2508", - name: "Codestral", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 16384 }, - }, - "gemma-3-1b-it": { - id: "gemma-3-1b-it", - name: "Gemma 3 1B IT", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.3 }, - limit: { context: 1000000, output: 16384 }, - }, - "glm-4-32b-0414-128k": { - id: "glm-4-32b-0414-128k", - name: "GLM-4 32B (0414-128k)", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 128000, output: 16384 }, - }, - "seed-1-6-flash-250715": { - id: "seed-1-6-flash-250715", - name: "Seed 1.6 Flash (250715)", - family: "seed", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-26", - last_updated: "2025-07-26", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.3, cache_read: 0.01 }, - limit: { context: 256000, output: 8192 }, - }, - "seed-1-6-250615": { - id: "seed-1-6-250615", - name: "Seed 1.6 (250615)", - family: "seed", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-06-25", - last_updated: "2025-06-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2, cache_read: 0.05 }, - limit: { context: 256000, output: 8192 }, - }, - "qwen3-vl-235b-a22b-thinking": { - id: "qwen3-vl-235b-a22b-thinking", - name: "Qwen3 VL 235B A22B Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-vl-30b-a3b-thinking": { - id: "qwen3-vl-30b-a3b-thinking", - name: "Qwen3 VL 30B A3B Thinking", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-02", - last_updated: "2025-10-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen2-5-vl-32b-instruct": { - id: "qwen2-5-vl-32b-instruct", - name: "Qwen2.5 VL 32B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-03-15", - last_updated: "2025-03-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.3 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen3-vl-8b-instruct": { - id: "qwen3-vl-8b-instruct", - name: "Qwen3 VL 8B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-08-19", - last_updated: "2025-08-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "claude-3-7-sonnet": { - id: "claude-3-7-sonnet", - name: "Claude 3.7 Sonnet", - family: "claude", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-02-24", - last_updated: "2025-02-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3 }, - limit: { context: 200000, output: 8192 }, - }, - "gemini-pro-latest": { - id: "gemini-pro-latest", - name: "Gemini Pro Latest", - family: "gemini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-27", - last_updated: "2026-02-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-3-5-haiku": { - id: "claude-3-5-haiku", - name: "Claude 3.5 Haiku", - family: "claude", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08 }, - limit: { context: 200000, output: 8192 }, - status: "deprecated", - }, - "qwen-max-latest": { - id: "qwen-max-latest", - name: "Qwen Max Latest", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 6.4 }, - limit: { context: 32768, output: 8192 }, - }, - "glm-4.6v-flash": { - id: "glm-4.6v-flash", - name: "GLM-4.6V Flash", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16000 }, - status: "beta", - }, - "qwen3-30b-a3b-instruct-2507": { - id: "qwen3-30b-a3b-instruct-2507", - name: "Qwen3 30B A3B Instruct (2507)", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "minimax-text-01": { - id: "minimax-text-01", - name: "MiniMax Text 01", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-01-15", - last_updated: "2025-01-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1 }, - limit: { context: 1000000, output: 131072 }, - }, - "qwen3-32b-fp8": { - id: "qwen3-32b-fp8", - name: "Qwen3 32B FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "llama-4-scout-17b-instruct": { - id: "llama-4-scout-17b-instruct", - name: "Llama 4 Scout 17B Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.66 }, - limit: { context: 8192, output: 2048 }, - }, - "qwen3-4b-fp8": { - id: "qwen3-4b-fp8", - name: "Qwen3 4B FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.05 }, - limit: { context: 131072, output: 8192 }, - }, - "ministral-8b-2512": { - id: "ministral-8b-2512", - name: "Ministral 8B", - family: "mistral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 262144, output: 8192 }, - }, - "gemma-3-27b": { - id: "gemma-3-27b", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.27 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-vl-flash": { - id: "qwen3-vl-flash", - name: "Qwen3 VL Flash", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-09", - last_updated: "2025-10-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.01 }, - limit: { context: 1000000, output: 32000 }, - }, - "llama-3.1-70b-instruct": { - id: "llama-3.1-70b-instruct", - name: "Llama 3.1 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 128000, output: 2048 }, - status: "beta", - }, - "seed-1-8-251228": { - id: "seed-1-8-251228", - name: "Seed 1.8 (251228)", - family: "seed", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-18", - last_updated: "2025-12-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2, cache_read: 0.05 }, - limit: { context: 256000, output: 8192 }, - }, - "qwen3-235b-a22b-thinking-2507": { - id: "qwen3-235b-a22b-thinking-2507", - name: "Qwen3 235B A22B Thinking (2507)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "seed-1-6-250915": { - id: "seed-1-6-250915", - name: "Seed 1.6 (250915)", - family: "seed", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 2, cache_read: 0.05 }, - limit: { context: 256000, output: 8192 }, - }, - "glm-4.5-x": { - id: "glm-4.5-x", - name: "GLM-4.5 X", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2.2, output: 8.9, cache_read: 0.45 }, - limit: { context: 128000, output: 16384 }, - status: "beta", - }, - "qwen3-30b-a3b-thinking-2507": { - id: "qwen3-30b-a3b-thinking-2507", - name: "Qwen3 30B A3B Thinking (2507)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-08", - last_updated: "2025-07-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "Grok 4 Fast Reasoning", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "deepseek-v3.1": { - id: "deepseek-v3.1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68, cache_read: 0.11 }, - limit: { context: 128000, output: 32768 }, - }, - "ministral-3b-2512": { - id: "ministral-3b-2512", - name: "Ministral 3B", - family: "mistral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "qwen-plus-latest": { - id: "qwen-plus-latest", - name: "Qwen Plus Latest", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-01-25", - last_updated: "2025-01-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 131072, output: 8192 }, - }, - "llama-3.1-nemotron-ultra-253b": { - id: "llama-3.1-nemotron-ultra-253b", - name: "Llama 3.1 Nemotron Ultra 253B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-04-07", - last_updated: "2025-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 128000, output: 8192 }, - }, - "llama-4-maverick-17b-instruct": { - id: "llama-4-maverick-17b-instruct", - name: "Llama 4 Maverick 17B Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.24, output: 0.97 }, - limit: { context: 8192, output: 2048 }, - }, - "grok-4-0709": { - id: "grok-4-0709", - name: "Grok 4 (0709)", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 256000, output: 256000 }, - }, - "qwen3-30b-a3b-fp8": { - id: "qwen3-30b-a3b-fp8", - name: "Qwen3 30B A3B FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "minimax-m2.1-lightning": { - id: "minimax-m2.1-lightning", - name: "MiniMax M2.1 Lightning", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.48 }, - limit: { context: 196608, output: 131072 }, - }, - "qwen3-max-2026-01-23": { - id: "qwen3-max-2026-01-23", - name: "Qwen3 Max (2026-01-23)", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-01-23", - last_updated: "2026-01-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.6 }, - limit: { context: 256000, output: 32800 }, - }, - "llama-3.2-3b-instruct": { - id: "llama-3.2-3b-instruct", - name: "Llama 3.2 3B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-09-18", - last_updated: "2024-09-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.05 }, - limit: { context: 32768, output: 32000 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "Qwen3 Coder Next", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4 }, - limit: { context: 262144, output: 65536 }, - }, - "gpt-4o-search-preview": { - id: "gpt-4o-search-preview", - name: "GPT-4o Search Preview", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 16384 }, - }, - custom: { - id: "custom", - name: "Custom Model", - family: "auto", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-01-01", - last_updated: "2024-01-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-vl-30b-a3b-instruct": { - id: "qwen3-vl-30b-a3b-instruct", - name: "Qwen3 VL 30B A3B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-10-02", - last_updated: "2025-10-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 131072, output: 8192 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 0.42, cache_read: 0.03 }, - limit: { context: 163840, output: 16384 }, - }, - "qwen3-235b-a22b-fp8": { - id: "qwen3-235b-a22b-fp8", - name: "Qwen3 235B A22B FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.5 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.5 }, - limit: { context: 131072, output: 32766 }, - }, - "kimi-k2": { - id: "kimi-k2", - name: "Kimi K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.5 }, - limit: { context: 131072, output: 16384 }, - }, - "llama-3-8b-instruct": { - id: "llama-3-8b-instruct", - name: "Llama 3 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-04-03", - last_updated: "2025-04-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 8192, output: 8192 }, - }, - "qwen3-vl-235b-a22b-instruct": { - id: "qwen3-vl-235b-a22b-instruct", - name: "Qwen3 VL 235B A22B Instruct", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.75 }, - limit: { context: 131072, output: 32766 }, - }, - "qwen25-coder-7b": { - id: "qwen25-coder-7b", - name: "Qwen2.5 Coder 7B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-09-19", - last_updated: "2024-09-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.05 }, - limit: { context: 131072, output: 8192 }, - }, - "llama-3.1-8b-instruct": { - id: "llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.22 }, - limit: { context: 128000, output: 2048 }, - status: "beta", - }, - "llama-3-70b-instruct": { - id: "llama-3-70b-instruct", - name: "Llama 3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.51, output: 0.74 }, - limit: { context: 8192, output: 8000 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek R1 (0528)", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 64000, output: 16384 }, - status: "beta", - }, - "glm-4.5-airx": { - id: "glm-4.5-airx", - name: "GLM-4.5 AirX", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.5, cache_read: 0.22 }, - limit: { context: 128000, output: 16384 }, - }, - "ministral-14b-2512": { - id: "ministral-14b-2512", - name: "Ministral 14B", - family: "mistral", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2025-12-02", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 262144, output: 8192 }, - }, - "llama-3.2-11b-instruct": { - id: "llama-3.2-11b-instruct", - name: "Llama 3.2 11B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.33 }, - limit: { context: 128000, output: 8192 }, - }, - "claude-3-opus": { - id: "claude-3-opus", - name: "Claude 3 Opus", - family: "claude", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2024-03-04", - last_updated: "2024-03-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5 }, - limit: { context: 200000, output: 4096 }, - }, - "minimax-m2.7": { - id: "minimax-m2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "grok-4-20-beta-0309-non-reasoning": { - id: "grok-4-20-beta-0309-non-reasoning", - name: "Grok 4.20 (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12, cache_read: 0.4 } }, - limit: { context: 2000000, output: 30000 }, - }, - "qwen3-coder-plus": { - id: "qwen3-coder-plus", - name: "Qwen3 Coder Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 5 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview 09-25", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-k2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "mistral-large-2512": { - id: "mistral-large-2512", - name: "Mistral Large 3", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 262144, output: 262144 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "minimax-m2.7-highspeed": { - id: "minimax-m2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "gemma-3n-e4b-it": { - id: "gemma-3n-e4b-it", - name: "Gemma 3n 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "claude-3-5-sonnet-20241022": { - id: "claude-3-5-sonnet-20241022", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "gpt-5.2-pro": { - id: "gpt-5.2-pro", - name: "GPT-5.2 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 21, output: 168 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "qwq-plus": { - id: "qwq-plus", - name: "QwQ Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 2.4 }, - limit: { context: 131072, output: 8192 }, - }, - "gemini-3.1-flash-lite-preview": { - id: "gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "qwen-vl-plus": { - id: "qwen-vl-plus", - name: "Qwen-VL Plus", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-08-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.21, output: 0.63 }, - limit: { context: 131072, output: 8192 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "devstral-2512": { - id: "devstral-2512", - name: "Devstral 2", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen3-32b": { - id: "qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.7, output: 2.8, reasoning: 8.4 }, - limit: { context: 131072, output: 16384 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "glm-4.7-flashx": { - id: "glm-4.7-flashx", - name: "GLM-4.7-FlashX", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4, cache_read: 0.01, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "qwen35-397b-a17b": { - id: "qwen35-397b-a17b", - name: "Qwen3.5 397B-A17B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-02-15", - last_updated: "2026-02-15", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-max": { - id: "qwen-max", - name: "Qwen Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-03", - last_updated: "2025-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.6, output: 6.4 }, - limit: { context: 32768, output: 8192 }, - }, - "gpt-5.3-chat-latest": { - id: "gpt-5.3-chat-latest", - name: "GPT-5.3 Chat (latest)", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "gemini-2.0-flash": { - id: "gemini-2.0-flash", - name: "Gemini 2.0 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 8192 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.5, - output: 3, - cache_read: 0.05, - context_over_200k: { input: 0.5, output: 3, cache_read: 0.05 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "qwen-plus": { - id: "qwen-plus", - name: "Qwen Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-01-25", - last_updated: "2025-09-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.2, reasoning: 4 }, - limit: { context: 1000000, output: 32768 }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - experimental: { - modes: { - fast: { - cost: { input: 12.5, output: 75, cache_read: 1.25 }, - provider: { body: { service_tier: "priority" } }, - }, - }, - }, - }, - "qwen3.6-35b-a3b": { - id: "qwen3.6-35b-a3b", - name: "Qwen3.6 35B-A3B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-17", - last_updated: "2026-04-17", - modalities: { input: ["text", "image", "video", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.248, output: 1.485 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen-omni-turbo": { - id: "qwen-omni-turbo", - name: "Qwen-Omni Turbo", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-01-19", - last_updated: "2025-03-26", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.07, output: 0.27, input_audio: 4.44, output_audio: 8.89 }, - limit: { context: 32768, output: 2048 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 262144, output: 131072 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "minimax-m2": { - id: "minimax-m2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196608, output: 128000 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen-flash": { - id: "qwen-flash", - name: "Qwen Flash", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4 }, - limit: { context: 1000000, output: 32768 }, - }, - "gpt-4-turbo": { - id: "gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1048576, output: 131072 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "sonar-pro": { - id: "sonar-pro", - name: "Sonar Pro", - family: "sonar-pro", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15 }, - limit: { context: 200000, output: 8192 }, - }, - "pixtral-large-latest": { - id: "pixtral-large-latest", - name: "Pixtral Large (latest)", - family: "pixtral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2024-11-04", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 128000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-4-20-beta-0309-reasoning": { - id: "grok-4-20-beta-0309-reasoning", - name: "Grok 4.20 (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-09", - last_updated: "2026-03-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6, cache_read: 0.2, context_over_200k: { input: 4, output: 12, cache_read: 0.4 } }, - limit: { context: 2000000, output: 30000 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3.6-plus": { - id: "qwen3.6-plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.276, output: 1.651, cache_read: 0.028, cache_write: 0.344 }, - limit: { context: 1000000, output: 65536 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "qwen3-max": { - id: "qwen3-max", - name: "Qwen3 Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.2, output: 6 }, - limit: { context: 262144, output: 65536 }, - }, - "minimax-m2.1": { - id: "minimax-m2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 6, output: 24, cache_read: 1.3, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "mistral-large-latest": { - id: "mistral-large-latest", - name: "Mistral Large (latest)", - family: "mistral-large", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2024-11-01", - last_updated: "2025-12-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 262144, output: 262144 }, - }, - "mistral-small-2506": { - id: "mistral-small-2506", - name: "Mistral Small 3.2", - family: "mistral-small", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-06-20", - last_updated: "2025-06-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "gemma-3-12b-it": { - id: "gemma-3-12b-it", - name: "Gemma 3 12B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5.2-chat-latest": { - id: "gpt-5.2-chat-latest", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "gemma-3n-e2b-it": { - id: "gemma-3n-e2b-it", - name: "Gemma 3n 2B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex mini", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-4-fast": { - id: "grok-4-fast", - name: "Grok 4 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "gemini-3.1-flash-lite": { - id: "gemini-3.1-flash-lite", - name: "Gemini 3.1 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-05-07", - last_updated: "2026-05-07", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "qwen3-next-80b-a3b-thinking": { - id: "qwen3-next-80b-a3b-thinking", - name: "Qwen3-Next 80B-A3B (Thinking)", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 6 }, - limit: { context: 131072, output: 32768 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemma-3-4b-it": { - id: "gemma-3-4b-it", - name: "Gemma 3 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.15, output: 8, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - o1: { - id: "o1", - name: "o1", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1, cache_read: 0.03, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-3.5-turbo": { - id: "gpt-3.5-turbo", - name: "GPT-3.5-turbo", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2021-09-01", - release_date: "2023-03-01", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5, cache_read: 1.25 }, - limit: { context: 16385, output: 4096 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "qwen-vl-max": { - id: "qwen-vl-max", - name: "Qwen-VL Max", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-04-08", - last_updated: "2025-08-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.2 }, - limit: { context: 131072, output: 8192 }, - }, - sonar: { - id: "sonar", - name: "Sonar", - family: "sonar", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 1 }, - limit: { context: 128000, output: 4096 }, - }, - "qwen3-coder-flash": { - id: "qwen3-coder-flash", - name: "Qwen3 Coder Flash", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 1.5 }, - limit: { context: 1000000, output: 65536 }, - }, - "grok-4-3": { - id: "grok-4-3", - name: "Grok 4.3", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-05-01", - last_updated: "2026-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 2.5, - cache_read: 0.2, - context_over_200k: { input: 2.5, output: 5, cache_read: 0.4 }, - }, - limit: { context: 1000000, output: 30000 }, - }, - "glm-4.5v": { - id: "glm-4.5v", - name: "GLM-4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 64000, output: 16384 }, - }, - "deepseek-v4-flash": { - id: "deepseek-v4-flash", - name: "DeepSeek V4 Flash", - family: "deepseek-flash", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.28, cache_read: 0.028 }, - limit: { context: 1000000, output: 384000 }, - }, - "grok-4": { - id: "grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, reasoning: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "qwen3-next-80b-a3b-instruct": { - id: "qwen3-next-80b-a3b-instruct", - name: "Qwen3-Next 80B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09", - last_updated: "2025-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2 }, - limit: { context: 131072, output: 32768 }, - }, - "gpt-4": { - id: "gpt-4", - name: "GPT-4", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - knowledge: "2023-11", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 60 }, - limit: { context: 8192, output: 8192 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "glm-4.6v": { - id: "glm-4.6v", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 128000, output: 32768 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 15, cache_read: 0.25 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "glm-4.5-flash": { - id: "glm-4.5-flash", - name: "GLM-4.5-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "qwen3-vl-plus": { - id: "qwen3-vl-plus", - name: "Qwen3-VL Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-23", - last_updated: "2025-09-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.6, reasoning: 4.8 }, - limit: { context: 262144, output: 32768 }, - }, - "grok-4-1-fast": { - id: "grok-4-1-fast", - name: "Grok 4.1 Fast", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-coder-480b-a35b-instruct": { - id: "qwen3-coder-480b-a35b-instruct", - name: "Qwen3-Coder 480B-A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.5, output: 7.5 }, - limit: { context: 262144, output: 65536 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "deepseek-v4-pro": { - id: "deepseek-v4-pro", - name: "DeepSeek V4 Pro", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-05", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.74, output: 3.48, cache_read: 0.145 }, - limit: { context: 1000000, output: 384000 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "GPT-4.1 nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03 }, - limit: { context: 1047576, output: 32768 }, - }, - "claude-3-7-sonnet-20250219": { - id: "claude-3-7-sonnet-20250219", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "qwen3-coder-30b-a3b-instruct": { - id: "qwen3-coder-30b-a3b-instruct", - name: "Qwen3-Coder 30B-A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.45, output: 2.25 }, - limit: { context: 262144, output: 65536 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - o3: { - id: "o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, input: 272000, output: 272000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "minimax-m2.5-highspeed": { - id: "minimax-m2.5-highspeed", - name: "MiniMax-M2.5-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen-turbo": { - id: "qwen-turbo", - name: "Qwen Turbo", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-11-01", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.2, reasoning: 0.5 }, - limit: { context: 1000000, output: 16384 }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5 (latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "glm-4.7-flash": { - id: "glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen3.6-max-preview": { - id: "qwen3.6-max-preview", - name: "Qwen3.6 Max Preview", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.3, output: 7.8, cache_read: 0.13, cache_write: 1.625 }, - limit: { context: 262144, output: 65536 }, - }, - "gpt-5-chat-latest": { - id: "gpt-5-chat-latest", - name: "GPT-5 Chat (latest)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "qwen2-5-vl-72b-instruct": { - id: "qwen2-5-vl-72b-instruct", - name: "Qwen2.5-VL 72B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.8, output: 8.4 }, - limit: { context: 131072, output: 8192 }, - }, - "gpt-5.5-pro": { - id: "gpt-5.5-pro", - name: "GPT-5.5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-23", - last_updated: "2026-04-23", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "devstral-small-2507": { - id: "devstral-small-2507", - name: "Devstral Small", - family: "devstral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-07-10", - last_updated: "2025-07-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 128000 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 1048576, output: 8192 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-3": { - id: "grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - "sonar-reasoning-pro": { - id: "sonar-reasoning-pro", - name: "Sonar Reasoning Pro", - family: "sonar-reasoning", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-09-01", - release_date: "2024-01-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8 }, - limit: { context: 128000, output: 4096 }, - }, - }, - }, - "google-vertex": { - id: "google-vertex", - env: ["GOOGLE_VERTEX_PROJECT", "GOOGLE_VERTEX_LOCATION", "GOOGLE_APPLICATION_CREDENTIALS"], - npm: "@ai-sdk/google-vertex", - name: "Vertex", - doc: "https://cloud.google.com/vertex-ai/generative-ai/docs/models", - models: { - "gemini-2.0-flash": { - id: "gemini-2.0-flash", - name: "Gemini 2.0 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.025 }, - limit: { context: 1048576, output: 8192 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-flash-latest": { - id: "gemini-flash-latest", - name: "Gemini Flash Latest", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, cache_write: 0.383 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-lite-preview-06-17": { - id: "gemini-2.5-flash-lite-preview-06-17", - name: "Gemini 2.5 Flash Lite Preview 06-17", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 65536, output: 65536 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, cache_write: 0.383 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-preview-09-2025": { - id: "gemini-2.5-flash-preview-09-2025", - name: "Gemini 2.5 Flash Preview 09-25", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, cache_write: 0.383 }, - limit: { context: 1048576, output: 65536 }, - }, - "zai-org/glm-5-maas": { - id: "zai-org/glm-5-maas", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.1 }, - limit: { context: 202752, output: 131072 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "zai-org/glm-4.7-maas": { - id: "zai-org/glm-4.7-maas", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-06", - last_updated: "2026-01-06", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2 }, - limit: { context: 200000, output: 128000 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "deepseek-ai/deepseek-v3.2-maas": { - id: "deepseek-ai/deepseek-v3.2-maas", - name: "DeepSeek V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-12-17", - last_updated: "2026-04-04", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68, cache_read: 0.056 }, - limit: { context: 163840, output: 65536 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "deepseek-ai/deepseek-v3.1-maas": { - id: "deepseek-ai/deepseek-v3.1-maas", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text", "pdf"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.7 }, - limit: { context: 163840, output: 32768 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "openai/gpt-oss-120b-maas": { - id: "openai/gpt-oss-120b-maas", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.36 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-oss-20b-maas": { - id: "openai/gpt-oss-20b-maas", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.25 }, - limit: { context: 131072, output: 32768 }, - }, - "meta/llama-3.3-70b-instruct-maas": { - id: "meta/llama-3.3-70b-instruct-maas", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.72, output: 0.72 }, - limit: { context: 128000, output: 8192 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "meta/llama-4-maverick-17b-128e-instruct-maas": { - id: "meta/llama-4-maverick-17b-128e-instruct-maas", - name: "Llama 4 Maverick 17B 128E Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-29", - last_updated: "2025-04-29", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.15 }, - limit: { context: 524288, output: 8192 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "qwen/qwen3-235b-a22b-instruct-2507-maas": { - id: "qwen/qwen3-235b-a22b-instruct-2507-maas", - name: "Qwen3 235B A22B Instruct", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-13", - last_updated: "2025-08-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.22, output: 0.88 }, - limit: { context: 262144, output: 16384 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "moonshotai/kimi-k2-thinking-maas": { - id: "moonshotai/kimi-k2-thinking-maas", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5 }, - limit: { context: 262144, output: 262144 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}/endpoints/openapi", - }, - }, - "gemini-flash-lite-latest": { - id: "gemini-flash-lite-latest", - name: "Gemini Flash-Lite Latest", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-pro-preview-05-06": { - id: "gemini-2.5-pro-preview-05-06", - name: "Gemini 2.5 Pro Preview 05-06", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-05-06", - last_updated: "2025-05-06", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-haiku-4-5@20251001": { - id: "claude-haiku-4-5@20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-3.1-pro-preview-customtools": { - id: "gemini-3.1-pro-preview-customtools", - name: "Gemini 3.1 Pro Preview Custom Tools", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-sonnet-4-6@default": { - id: "claude-sonnet-4-6@default", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 3, - output: 15, - cache_read: 0.3, - cache_write: 3.75, - context_over_200k: { input: 6, output: 22.5, cache_read: 0.6, cache_write: 7.5 }, - }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview 09-25", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-3-5-haiku@20241022": { - id: "claude-3-5-haiku@20241022", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-3.1-flash-lite-preview": { - id: "gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-3-5-sonnet@20241022": { - id: "claude-3-5-sonnet@20241022", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-opus-4-1@20250805": { - id: "claude-opus-4-1@20250805", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.5, - output: 3, - cache_read: 0.05, - context_over_200k: { input: 0.5, output: 3, cache_read: 0.05 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-preview-05-20": { - id: "gemini-2.5-flash-preview-05-20", - name: "Gemini 2.5 Flash Preview 05-20", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-embedding-001": { - id: "gemini-embedding-001", - name: "Gemini Embedding 001", - family: "gemini", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-05", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0 }, - limit: { context: 2048, output: 3072 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-pro-preview-06-05": { - id: "gemini-2.5-pro-preview-06-05", - name: "Gemini 2.5 Pro Preview 06-05", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-sonnet-4@20250514": { - id: "claude-sonnet-4@20250514", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-3.1-flash-lite": { - id: "gemini-3.1-flash-lite", - name: "Gemini 3.1 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-05-07", - last_updated: "2026-05-07", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-3-7-sonnet@20250219": { - id: "claude-3-7-sonnet@20250219", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "claude-opus-4@20250514": { - id: "claude-opus-4@20250514", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "claude-opus-4-5@20251101": { - id: "claude-opus-4-5@20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-2.5-flash-preview-04-17": { - id: "gemini-2.5-flash-preview-04-17", - name: "Gemini 2.5 Flash Preview 04-17", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-04-17", - last_updated: "2025-04-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-sonnet-4-5@20250929": { - id: "claude-sonnet-4-5@20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-opus-4-6@default": { - id: "claude-opus-4-6@default", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 1048576, output: 8192 }, - }, - "claude-opus-4-7@default": { - id: "claude-opus-4-7@default", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 1000000, output: 128000 }, - provider: { npm: "@ai-sdk/google-vertex/anthropic" }, - }, - }, - }, - "cloudflare-workers-ai": { - id: "cloudflare-workers-ai", - env: ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1", - name: "Cloudflare Workers AI", - doc: "https://developers.cloudflare.com/workers-ai/models/", - models: { - "@cf/zai-org/glm-4.7-flash": { - id: "@cf/zai-org/glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.06, output: 0.4 }, - limit: { context: 131072, output: 131072 }, - }, - "@cf/nvidia/nemotron-3-120b-a12b": { - id: "@cf/nvidia/nemotron-3-120b-a12b", - name: "Nemotron 3 Super 120B", - family: "nemotron", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-03-11", - last_updated: "2026-03-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 256000, output: 256000 }, - }, - "@cf/openai/gpt-oss-20b": { - id: "@cf/openai/gpt-oss-20b", - name: "GPT OSS 20B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.3 }, - limit: { context: 128000, output: 16384 }, - }, - "@cf/openai/gpt-oss-120b": { - id: "@cf/openai/gpt-oss-120b", - name: "GPT OSS 120B", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 0.75 }, - limit: { context: 128000, output: 16384 }, - }, - "@cf/meta/llama-4-scout-17b-16e-instruct": { - id: "@cf/meta/llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.27, output: 0.85 }, - limit: { context: 128000, output: 16384 }, - }, - "@cf/google/gemma-4-26b-a4b-it": { - id: "@cf/google/gemma-4-26b-a4b-it", - name: "Gemma 4 26B A4B IT", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-15", - last_updated: "2025-12-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 256000, output: 16384 }, - }, - "@cf/moonshotai/kimi-k2.5": { - id: "@cf/moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 256000, output: 256000 }, - }, - "@cf/moonshotai/kimi-k2.6": { - id: "@cf/moonshotai/kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 256000, output: 256000 }, - }, - }, - }, - groq: { - id: "groq", - env: ["GROQ_API_KEY"], - npm: "@ai-sdk/groq", - name: "Groq", - doc: "https://console.groq.com/docs/models", - models: { - "gemma2-9b-it": { - id: "gemma2-9b-it", - name: "Gemma 2 9B", - family: "gemma", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-06-27", - last_updated: "2024-06-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 8192, output: 8192 }, - status: "deprecated", - }, - "mistral-saba-24b": { - id: "mistral-saba-24b", - name: "Mistral Saba 24B", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-02-06", - last_updated: "2025-02-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.79, output: 0.79 }, - limit: { context: 32768, output: 32768 }, - status: "deprecated", - }, - "deepseek-r1-distill-llama-70b": { - id: "deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.75, output: 0.99 }, - limit: { context: 131072, output: 8192 }, - status: "deprecated", - }, - "llama-guard-3-8b": { - id: "llama-guard-3-8b", - name: "Llama Guard 3 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 8192, output: 8192 }, - status: "deprecated", - }, - "llama-3.3-70b-versatile": { - id: "llama-3.3-70b-versatile", - name: "Llama 3.3 70B Versatile", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.59, output: 0.79 }, - limit: { context: 131072, output: 32768 }, - }, - "allam-2-7b": { - id: "allam-2-7b", - name: "ALLaM-2-7b", - family: "allam", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-09", - release_date: "2024-09", - last_updated: "2024-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 4096, output: 4096 }, - }, - "whisper-large-v3": { - id: "whisper-large-v3", - name: "Whisper Large V3", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-09", - release_date: "2023-09-01", - last_updated: "2025-09-05", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 448, output: 448 }, - }, - "llama-3.1-8b-instant": { - id: "llama-3.1-8b-instant", - name: "Llama 3.1 8B Instant", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.08 }, - limit: { context: 131072, output: 131072 }, - }, - "llama3-70b-8192": { - id: "llama3-70b-8192", - name: "Llama 3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-03", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.59, output: 0.79 }, - limit: { context: 8192, output: 8192 }, - status: "deprecated", - }, - "qwen-qwq-32b": { - id: "qwen-qwq-32b", - name: "Qwen QwQ 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-11-27", - last_updated: "2024-11-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 0.39 }, - limit: { context: 131072, output: 16384 }, - status: "deprecated", - }, - "whisper-large-v3-turbo": { - id: "whisper-large-v3-turbo", - name: "Whisper Large v3 Turbo", - family: "whisper", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 448, output: 448 }, - }, - "llama3-8b-8192": { - id: "llama3-8b-8192", - name: "Llama 3 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-03", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.08 }, - limit: { context: 8192, output: 8192 }, - status: "deprecated", - }, - "canopylabs/orpheus-arabic-saudi": { - id: "canopylabs/orpheus-arabic-saudi", - name: "Orpheus Arabic Saudi", - family: "canopylabs", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-12-16", - release_date: "2025-12-16", - last_updated: "2025-12-16", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - cost: { input: 40, output: 0 }, - limit: { context: 4000, output: 50000 }, - }, - "canopylabs/orpheus-v1-english": { - id: "canopylabs/orpheus-v1-english", - name: "Orpheus V1 English", - family: "canopylabs", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2025-12-19", - release_date: "2025-12-19", - last_updated: "2025-12-19", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 4000, output: 50000 }, - }, - "meta-llama/llama-4-scout-17b-16e-instruct": { - id: "meta-llama/llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11, output: 0.34 }, - limit: { context: 131072, output: 8192 }, - }, - "meta-llama/llama-prompt-guard-2-22m": { - id: "meta-llama/llama-prompt-guard-2-22m", - name: "Llama Prompt Guard 2 22M", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.03 }, - limit: { context: 512, output: 512 }, - }, - "meta-llama/llama-guard-4-12b": { - id: "meta-llama/llama-guard-4-12b", - name: "Llama Guard 4 12B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.2 }, - limit: { context: 131072, output: 1024 }, - status: "deprecated", - }, - "meta-llama/llama-4-maverick-17b-128e-instruct": { - id: "meta-llama/llama-4-maverick-17b-128e-instruct", - name: "Llama 4 Maverick 17B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 131072, output: 8192 }, - status: "deprecated", - }, - "meta-llama/llama-prompt-guard-2-86m": { - id: "meta-llama/llama-prompt-guard-2-86m", - name: "Llama Prompt Guard 2 86M", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2024-10-01", - last_updated: "2024-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 512, output: 512 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-oss-safeguard-20b": { - id: "openai/gpt-oss-safeguard-20b", - name: "Safety GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-03-05", - last_updated: "2025-03-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3, cache_read: 0.037 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 65536 }, - }, - "qwen/qwen3-32b": { - id: "qwen/qwen3-32b", - name: "Qwen3 32B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11-08", - release_date: "2024-12-23", - last_updated: "2024-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.29, output: 0.59 }, - limit: { context: 131072, output: 40960 }, - }, - "groq/compound": { - id: "groq/compound", - name: "Compound", - family: "groq", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09-04", - release_date: "2025-09-04", - last_updated: "2025-09-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "groq/compound-mini": { - id: "groq/compound-mini", - name: "Compound Mini", - family: "groq", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09-04", - release_date: "2025-09-04", - last_updated: "2025-09-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "moonshotai/kimi-k2-instruct": { - id: "moonshotai/kimi-k2-instruct", - name: "Kimi K2 Instruct", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-14", - last_updated: "2025-07-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 131072, output: 16384 }, - status: "deprecated", - }, - "moonshotai/kimi-k2-instruct-0905": { - id: "moonshotai/kimi-k2-instruct-0905", - name: "Kimi K2 Instruct 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3 }, - limit: { context: 262144, output: 16384 }, - }, - }, - }, - azure: { - id: "azure", - env: ["AZURE_RESOURCE_NAME", "AZURE_API_KEY"], - npm: "@ai-sdk/azure", - name: "Azure", - doc: "https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models", - models: { - "mistral-nemo": { - id: "mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 128000, output: 128000 }, - }, - "gpt-5.2-chat": { - id: "gpt-5.2-chat", - name: "GPT-5.2 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "codex-mini": { - id: "codex-mini", - name: "Codex Mini", - family: "gpt-codex-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-04", - release_date: "2025-05-16", - last_updated: "2025-05-16", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 6, cache_read: 0.375 }, - limit: { context: 200000, output: 100000 }, - }, - "phi-4-multimodal": { - id: "phi-4-multimodal", - name: "Phi-4-multimodal", - family: "phi", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0.08, output: 0.32, input_audio: 4 }, - limit: { context: 128000, output: 4096 }, - }, - "phi-3.5-mini-instruct": { - id: "phi-3.5-mini-instruct", - name: "Phi-3.5-mini-instruct", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 128000, output: 4096 }, - }, - "llama-4-scout-17b-16e-instruct": { - id: "llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.78 }, - limit: { context: 128000, output: 8192 }, - }, - "grok-4-1-fast-reasoning": { - id: "grok-4-1-fast-reasoning", - name: "Grok 4.1 Fast (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-06-27", - last_updated: "2025-06-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 128000, input: 128000, output: 8192 }, - status: "beta", - }, - "phi-3-medium-4k-instruct": { - id: "phi-3-medium-4k-instruct", - name: "Phi-3-medium-instruct (4k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 4096, output: 1024 }, - }, - "ministral-3b": { - id: "ministral-3b", - name: "Ministral 3B", - family: "ministral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.04, output: 0.04 }, - limit: { context: 128000, output: 8192 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-02-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "meta-llama-3.1-8b-instruct": { - id: "meta-llama-3.1-8b-instruct", - name: "Meta-Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.61 }, - limit: { context: 128000, output: 32768 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-06", - last_updated: "2026-02-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3 }, - limit: { context: 262144, output: 262144 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", - shape: "completions", - }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.71, output: 0.71 }, - limit: { context: 128000, output: 32768 }, - }, - "deepseek-v3-0324": { - id: "deepseek-v3-0324", - name: "DeepSeek-V3-0324", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.14, output: 4.56 }, - limit: { context: 131072, output: 131072 }, - }, - "gpt-5-chat": { - id: "gpt-5-chat", - name: "GPT-5 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2024-10-24", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 128000, output: 16384 }, - }, - "phi-3.5-moe-instruct": { - id: "phi-3.5-moe-instruct", - name: "Phi-3.5-MoE-instruct", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.16, output: 0.64 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5.3-chat": { - id: "gpt-5.3-chat", - name: "GPT-5.3 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 128000, output: 16384 }, - }, - "o1-mini": { - id: "o1-mini", - name: "o1-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 128000, output: 65536 }, - }, - "text-embedding-3-large": { - id: "text-embedding-3-large", - name: "text-embedding-3-large", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.13, output: 0 }, - limit: { context: 8191, output: 3072 }, - }, - "phi-3-mini-128k-instruct": { - id: "phi-3-mini-128k-instruct", - name: "Phi-3-mini-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 128000, output: 4096 }, - }, - "phi-4-reasoning": { - id: "phi-4-reasoning", - name: "Phi-4-reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 32000, output: 4096 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.03 }, - limit: { context: 272000, output: 128000 }, - }, - "gpt-5-nano": { - id: "gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.01 }, - limit: { context: 272000, output: 128000 }, - }, - "meta-llama-3-70b-instruct": { - id: "meta-llama-3-70b-instruct", - name: "Meta-Llama-3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.68, output: 3.54 }, - limit: { context: 8192, output: 2048 }, - }, - "phi-3-small-8k-instruct": { - id: "phi-3-small-8k-instruct", - name: "Phi-3-small-instruct (8k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 8192, output: 2048 }, - }, - "gpt-5.3-codex": { - id: "gpt-5.3-codex", - name: "GPT-5.3 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-24", - last_updated: "2026-02-24", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "text-embedding-ada-002": { - id: "text-embedding-ada-002", - name: "text-embedding-ada-002", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2022-12-15", - last_updated: "2022-12-15", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0 }, - limit: { context: 8192, output: 1536 }, - }, - "llama-3.2-90b-vision-instruct": { - id: "llama-3.2-90b-vision-instruct", - name: "Llama-3.2-90B-Vision-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.04, output: 2.04 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek-r1": { - id: "deepseek-r1", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 163840, output: 163840 }, - }, - "grok-4-1-fast-non-reasoning": { - id: "grok-4-1-fast-non-reasoning", - name: "Grok 4.1 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-06-27", - last_updated: "2025-06-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 128000, input: 128000, output: 8192 }, - status: "beta", - }, - "deepseek-v3.2-speciale": { - id: "deepseek-v3.2-speciale", - name: "DeepSeek-V3.2-Speciale", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 1.68 }, - limit: { context: 128000, output: 128000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "mistral-large-2411": { - id: "mistral-large-2411", - name: "Mistral Large 24.11", - family: "mistral-large", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 128000, output: 32768 }, - }, - "claude-opus-4-1": { - id: "claude-opus-4-1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "cohere-command-a": { - id: "cohere-command-a", - name: "Command A", - family: "command-a", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 256000, output: 8000 }, - }, - "llama-3.2-11b-vision-instruct": { - id: "llama-3.2-11b-vision-instruct", - name: "Llama-3.2-11B-Vision-Instruct", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.37, output: 0.37 }, - limit: { context: 128000, output: 8192 }, - }, - "meta-llama-3.1-405b-instruct": { - id: "meta-llama-3.1-405b-instruct", - name: "Meta-Llama-3.1-405B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 5.33, output: 16 }, - limit: { context: 128000, output: 32768 }, - }, - "gpt-5.1-chat": { - id: "gpt-5.1-chat", - name: "GPT-5.1 Chat", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-4-turbo-vision": { - id: "gpt-4-turbo-vision", - name: "GPT-4 Turbo Vision", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-14", - last_updated: "2026-01-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.75, output: 14, cache_read: 0.175 }, - limit: { context: 400000, output: 128000 }, - }, - "cohere-embed-v-4-0": { - id: "cohere-embed-v-4-0", - name: "Embed v4", - family: "cohere-embed", - attachment: true, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2025-04-15", - last_updated: "2025-04-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0 }, - limit: { context: 128000, output: 1536 }, - }, - "gpt-5.1-codex-mini": { - id: "gpt-5.1-codex-mini", - name: "GPT-5.1 Codex Mini", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "gpt-3.5-turbo-0125": { - id: "gpt-3.5-turbo-0125", - name: "GPT-3.5 Turbo 0125", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 1.5 }, - limit: { context: 16384, output: 16384 }, - }, - "o1-preview": { - id: "o1-preview", - name: "o1-preview", - family: "o", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 16.5, output: 66, cache_read: 8.25 }, - limit: { context: 128000, output: 32768 }, - }, - "cohere-embed-v3-multilingual": { - id: "cohere-embed-v3-multilingual", - name: "Embed v3 Multilingual", - family: "cohere-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-11-07", - last_updated: "2023-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0 }, - limit: { context: 512, output: 1024 }, - }, - "grok-4-20-non-reasoning": { - id: "grok-4-20-non-reasoning", - name: "Grok 4.20 (Non-Reasoning)", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 262000, output: 8192 }, - status: "beta", - }, - "gpt-5.1": { - id: "gpt-5.1", - name: "GPT-5.1", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 272000, output: 128000 }, - }, - "grok-4-fast-reasoning": { - id: "grok-4-fast-reasoning", - name: "Grok 4 Fast (Reasoning)", - family: "grok", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - o1: { - id: "o1", - name: "o1", - family: "o", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2023-09", - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 60, cache_read: 7.5 }, - limit: { context: 200000, output: 100000 }, - }, - "mistral-small-2503": { - id: "mistral-small-2503", - name: "Mistral Small 3.1", - family: "mistral-small", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.3 }, - limit: { context: 128000, output: 32768 }, - }, - "model-router": { - id: "model-router", - name: "Model Router", - family: "model-router", - attachment: true, - reasoning: false, - tool_call: true, - release_date: "2025-05-19", - last_updated: "2025-11-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-3.5-turbo-1106": { - id: "gpt-3.5-turbo-1106", - name: "GPT-3.5 Turbo 1106", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-11-06", - last_updated: "2023-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 2 }, - limit: { context: 16384, output: 16384 }, - }, - "text-embedding-3-small": { - id: "text-embedding-3-small", - name: "text-embedding-3-small", - family: "text-embedding", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2024-01-25", - last_updated: "2024-01-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.02, output: 0 }, - limit: { context: 8191, output: 1536 }, - }, - "deepseek-v3.1": { - id: "deepseek-v3.1", - name: "DeepSeek-V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.56, output: 1.68 }, - limit: { context: 131072, output: 131072 }, - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-08-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "phi-3-mini-4k-instruct": { - id: "phi-3-mini-4k-instruct", - name: "Phi-3-mini-instruct (4k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.13, output: 0.52 }, - limit: { context: 4096, output: 1024 }, - }, - "meta-llama-3.1-70b-instruct": { - id: "meta-llama-3.1-70b-instruct", - name: "Meta-Llama-3.1-70B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.68, output: 3.54 }, - limit: { context: 128000, output: 32768 }, - }, - "phi-4-mini-reasoning": { - id: "phi-4-mini-reasoning", - name: "Phi-4-mini-reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-4": { - id: "gpt-4", - name: "GPT-4", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-03-14", - last_updated: "2023-03-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 60, output: 120 }, - limit: { context: 8192, output: 8192 }, - }, - "meta-llama-3-8b-instruct": { - id: "meta-llama-3-8b-instruct", - name: "Meta-Llama-3-8B-Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.61 }, - limit: { context: 8192, output: 2048 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4 }, - limit: { context: 262144, output: 262144 }, - provider: { - npm: "@ai-sdk/openai-compatible", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/models", - shape: "completions", - }, - }, - "gpt-5-codex": { - id: "gpt-5-codex", - name: "GPT-5-Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 400000, output: 128000 }, - }, - "phi-4-mini": { - id: "phi-4-mini", - name: "Phi-4-mini", - family: "phi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 128000, output: 4096 }, - }, - "grok-4-20-reasoning": { - id: "grok-4-20-reasoning", - name: "Grok 4.20 (Reasoning)", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-09", - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 6 }, - limit: { context: 262000, output: 8192 }, - status: "beta", - }, - "gpt-3.5-turbo-0301": { - id: "gpt-3.5-turbo-0301", - name: "GPT-3.5 Turbo 0301", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-03-01", - last_updated: "2023-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 4096, output: 4096 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 5, - output: 25, - cache_read: 0.5, - cache_write: 6.25, - context_over_200k: { input: 10, output: 37.5, cache_read: 1, cache_write: 12.5 }, - }, - limit: { context: 200000, output: 128000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "phi-3-small-128k-instruct": { - id: "phi-3-small-128k-instruct", - name: "Phi-3-small-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4096 }, - }, - "deepseek-v3.2": { - id: "deepseek-v3.2", - name: "DeepSeek-V3.2", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.58, output: 1.68 }, - limit: { context: 128000, output: 128000 }, - }, - "phi-3-medium-128k-instruct": { - id: "phi-3-medium-128k-instruct", - name: "Phi-3-medium-instruct (128k)", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.17, output: 0.68 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-3.5-turbo-0613": { - id: "gpt-3.5-turbo-0613", - name: "GPT-3.5 Turbo 0613", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-06-13", - last_updated: "2023-06-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 4 }, - limit: { context: 16384, output: 16384 }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "phi-4": { - id: "phi-4", - name: "Phi-4", - family: "phi", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-5": { - id: "gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.13 }, - limit: { context: 272000, output: 128000 }, - }, - "gpt-4-32k": { - id: "gpt-4-32k", - name: "GPT-4 32K", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-11", - release_date: "2023-03-14", - last_updated: "2023-03-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 60, output: 120 }, - limit: { context: 32768, output: 32768 }, - }, - "cohere-embed-v3-english": { - id: "cohere-embed-v3-english", - name: "Embed v3 English", - family: "cohere-embed", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2023-11-07", - last_updated: "2023-11-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0 }, - limit: { context: 512, output: 1024 }, - }, - "phi-4-reasoning-plus": { - id: "phi-4-reasoning-plus", - name: "Phi-4-reasoning-plus", - family: "phi", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.125, output: 0.5 }, - limit: { context: 32000, output: 4096 }, - }, - "mistral-medium-2505": { - id: "mistral-medium-2505", - name: "Mistral Medium 3", - family: "mistral-medium", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-05", - release_date: "2025-05-07", - last_updated: "2025-05-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2 }, - limit: { context: 128000, output: 128000 }, - }, - "gpt-3.5-turbo-instruct": { - id: "gpt-3.5-turbo-instruct", - name: "GPT-3.5 Turbo Instruct", - family: "gpt", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2021-08", - release_date: "2023-09-21", - last_updated: "2023-09-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.5, output: 2 }, - limit: { context: 4096, output: 4096 }, - }, - "deepseek-r1-0528": { - id: "deepseek-r1-0528", - name: "DeepSeek-R1-0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 163840, output: 163840 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-12-02", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "gpt-5.1-codex": { - id: "gpt-5.1-codex", - name: "GPT-5.1 Codex", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-14", - last_updated: "2025-11-14", - modalities: { input: ["text", "image", "audio"], output: ["text", "image", "audio"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "codestral-2501": { - id: "codestral-2501", - name: "Codestral 25.01", - family: "codestral", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 256000, output: 256000 }, - }, - "llama-4-maverick-17b-128e-instruct-fp8": { - id: "llama-4-maverick-17b-128e-instruct-fp8", - name: "Llama 4 Maverick 17B 128E Instruct FP8", - family: "llama", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-04-05", - last_updated: "2025-04-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.25, output: 1 }, - limit: { context: 128000, output: 8192 }, - }, - "mai-ds-r1": { - id: "mai-ds-r1", - name: "MAI-DS-R1", - family: "mai", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.35, output: 5.4 }, - limit: { context: 128000, output: 8192 }, - }, - "gpt-5.1-codex-max": { - id: "gpt-5.1-codex-max", - name: "GPT-5.1 Codex Max", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-11-13", - last_updated: "2025-11-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - provider: { - npm: "@ai-sdk/anthropic", - api: "https://${AZURE_RESOURCE_NAME}.services.ai.azure.com/anthropic/v1", - }, - }, - "gpt-5.5": { - id: "gpt-5.5", - name: "GPT-5.5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-12-01", - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 30, cache_read: 0.5, context_over_200k: { input: 10, output: 45, cache_read: 1 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-4-turbo": { - id: "gpt-4-turbo", - name: "GPT-4 Turbo", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2023-11-06", - last_updated: "2024-04-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 10, output: 30 }, - limit: { context: 128000, output: 4096 }, - }, - "gpt-4o-mini": { - id: "gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.08 }, - limit: { context: 128000, output: 16384 }, - }, - "gpt-5.4-mini": { - id: "gpt-5.4-mini", - name: "GPT-5.4 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 4.5, cache_read: 0.075 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "cohere-command-r-08-2024": { - id: "cohere-command-r-08-2024", - name: "Command R", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 128000, output: 4000 }, - }, - "o4-mini": { - id: "o4-mini", - name: "o4-mini", - family: "o-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.28 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5.4-nano": { - id: "gpt-5.4-nano", - name: "GPT-5.4 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.25, cache_read: 0.02 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "grok-code-fast-1": { - id: "grok-code-fast-1", - name: "Grok Code Fast 1", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2025-08-28", - last_updated: "2025-08-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 1.5, cache_read: 0.02 }, - limit: { context: 256000, output: 10000 }, - }, - "gpt-5.4-pro": { - id: "gpt-5.4-pro", - name: "GPT-5.4 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 30, output: 180, context_over_200k: { input: 60, output: 270 } }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "o3-mini": { - id: "o3-mini", - name: "o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2024-12-20", - last_updated: "2025-01-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1.1, output: 4.4, cache_read: 0.55 }, - limit: { context: 200000, output: 100000 }, - }, - "grok-4": { - id: "grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, reasoning: 15, cache_read: 0.75 }, - limit: { context: 256000, output: 64000 }, - }, - "gpt-5.4": { - id: "gpt-5.4", - name: "GPT-5.4", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 2.5, - output: 15, - cache_read: 0.25, - context_over_200k: { input: 5, output: 22.5, cache_read: 0.5 }, - }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "gpt-4.1-nano": { - id: "gpt-4.1-nano", - name: "GPT-4.1 nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.03 }, - limit: { context: 1047576, output: 32768 }, - }, - "grok-3-mini": { - id: "grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 0.5, reasoning: 0.5, cache_read: 0.075 }, - limit: { context: 131072, output: 8192 }, - }, - o3: { - id: "o3", - name: "o3", - family: "o", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2024-05", - release_date: "2025-04-16", - last_updated: "2025-04-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 200000, output: 100000 }, - }, - "gpt-5-pro": { - id: "gpt-5-pro", - name: "GPT-5 Pro", - family: "gpt-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2025-10-06", - last_updated: "2025-10-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 120 }, - limit: { context: 400000, output: 272000 }, - }, - "gpt-4o": { - id: "gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-09", - release_date: "2024-05-13", - last_updated: "2024-08-06", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2.5, output: 10, cache_read: 1.25 }, - limit: { context: 128000, output: 16384 }, - }, - "cohere-command-r-plus-08-2024": { - id: "cohere-command-r-plus-08-2024", - name: "Command R+", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-06-01", - release_date: "2024-08-30", - last_updated: "2024-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 10 }, - limit: { context: 128000, output: 4000 }, - }, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "gpt-4.1-mini": { - id: "gpt-4.1-mini", - name: "GPT-4.1 mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 1.6, cache_read: 0.1 }, - limit: { context: 1047576, output: 32768 }, - }, - "grok-3": { - id: "grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-11", - release_date: "2025-02-17", - last_updated: "2025-02-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75 }, - limit: { context: 131072, output: 8192 }, - }, - "grok-4-fast-non-reasoning": { - id: "grok-4-fast-non-reasoning", - name: "Grok 4 Fast (Non-Reasoning)", - family: "grok", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-19", - last_updated: "2025-09-19", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.2, output: 0.5, cache_read: 0.05 }, - limit: { context: 2000000, output: 30000 }, - }, - }, - }, - fastrouter: { - id: "fastrouter", - env: ["FASTROUTER_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://go.fastrouter.ai/api/v1", - name: "FastRouter", - doc: "https://fastrouter.ai/models", - models: { - "x-ai/grok-4": { - id: "x-ai/grok-4", - name: "Grok 4", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.75, cache_write: 15 }, - limit: { context: 256000, output: 64000 }, - }, - "deepseek-ai/deepseek-r1-distill-llama-70b": { - id: "deepseek-ai/deepseek-r1-distill-llama-70b", - name: "DeepSeek R1 Distill Llama 70B", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-01-23", - last_updated: "2025-01-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.14 }, - limit: { context: 131072, output: 131072 }, - }, - "openai/gpt-5-mini": { - id: "openai/gpt-5-mini", - name: "GPT-5 Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2, cache_read: 0.025 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-5-nano": { - id: "openai/gpt-5-nano", - name: "GPT-5 Nano", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.4, cache_read: 0.005 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.2 }, - limit: { context: 131072, output: 65536 }, - }, - "openai/gpt-5": { - id: "openai/gpt-5", - name: "GPT-5", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-01", - release_date: "2025-08-07", - last_updated: "2025-08-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.125 }, - limit: { context: 400000, output: 128000 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 32768 }, - }, - "z-ai/glm-5": { - id: "z-ai/glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 3.15 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen/qwen3-coder": { - id: "qwen/qwen3-coder", - name: "Qwen3 Coder", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 262144, output: 66536 }, - }, - "google/gemini-2.5-pro": { - id: "google/gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "google/gemini-2.5-flash": { - id: "google/gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "moonshotai/kimi-k2": { - id: "moonshotai/kimi-k2", - name: "Kimi K2", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-11", - last_updated: "2025-07-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 131072, output: 32768 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 8, cache_read: 0.5 }, - limit: { context: 1047576, output: 32768 }, - }, - "anthropic/claude-opus-4.1": { - id: "anthropic/claude-opus-4.1", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "anthropic/claude-sonnet-4": { - id: "anthropic/claude-sonnet-4", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - }, - }, - stackit: { - id: "stackit", - env: ["STACKIT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.openai-compat.model-serving.eu01.onstackit.cloud/v1", - name: "STACKIT", - doc: "https://docs.stackit.cloud/products/data-and-ai/ai-model-serving/basics/available-shared-models", - models: { - "Qwen/Qwen3-VL-Embedding-8B": { - id: "Qwen/Qwen3-VL-Embedding-8B", - name: "Qwen3-VL Embedding 8B", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: false, - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.09 }, - limit: { context: 32000, output: 4096 }, - }, - "Qwen/Qwen3-VL-235B-A22B-Instruct-FP8": { - id: "Qwen/Qwen3-VL-235B-A22B-Instruct-FP8", - name: "Qwen3-VL 235B", - family: "qwen", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.64, output: 1.91 }, - limit: { context: 218000, output: 8192 }, - }, - "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8": { - id: "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8", - name: "Llama 3.1 8B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.16, output: 0.27 }, - limit: { context: 128000, output: 8192 }, - }, - "neuralmagic/Mistral-Nemo-Instruct-2407-FP8": { - id: "neuralmagic/Mistral-Nemo-Instruct-2407-FP8", - name: "Mistral Nemo", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2024-07-01", - last_updated: "2024-07-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.49, output: 0.71 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT-OSS 120B", - family: "gpt", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.49, output: 0.71 }, - limit: { context: 131000, output: 8192 }, - }, - "cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic": { - id: "cortecs/Llama-3.3-70B-Instruct-FP8-Dynamic", - name: "Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2024-12-05", - last_updated: "2024-12-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.49, output: 0.71 }, - limit: { context: 128000, output: 8192 }, - }, - "google/gemma-3-27b-it": { - id: "google/gemma-3-27b-it", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - release_date: "2025-05-17", - last_updated: "2025-05-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.49, output: 0.71 }, - limit: { context: 37000, output: 8192 }, - }, - "intfloat/e5-mistral-7b-instruct": { - id: "intfloat/e5-mistral-7b-instruct", - name: "E5 Mistral 7B", - family: "mistral", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: false, - release_date: "2023-12-11", - last_updated: "2023-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.02, output: 0.02 }, - limit: { context: 4096, output: 4096 }, - }, - }, - }, - "tencent-coding-plan": { - id: "tencent-coding-plan", - env: ["TENCENT_CODING_PLAN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.lkeap.cloud.tencent.com/coding/v3", - name: "Tencent Coding Plan (China)", - doc: "https://cloud.tencent.com/document/product/1772/128947", - models: { - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi-K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 202752, output: 16384 }, - }, - "hunyuan-turbos": { - id: "hunyuan-turbos", - name: "Hunyuan-TurboS", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-08", - last_updated: "2026-03-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 16384 }, - }, - "hunyuan-t1": { - id: "hunyuan-t1", - name: "Hunyuan-T1", - family: "hunyuan", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-03-08", - last_updated: "2026-03-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 16384 }, - }, - "hunyuan-2.0-instruct": { - id: "hunyuan-2.0-instruct", - name: "Tencent HY 2.0 Instruct", - family: "hunyuan", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-08", - last_updated: "2026-03-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 16384 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 204800, output: 32768 }, - }, - "tc-code-latest": { - id: "tc-code-latest", - name: "Auto", - family: "auto", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-03-08", - last_updated: "2026-03-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 16384 }, - }, - "hunyuan-2.0-thinking": { - id: "hunyuan-2.0-thinking", - name: "Tencent HY 2.0 Think", - family: "hunyuan", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-03-08", - last_updated: "2026-03-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 16384 }, - }, - }, - }, - "privatemode-ai": { - id: "privatemode-ai", - env: ["PRIVATEMODE_API_KEY", "PRIVATEMODE_ENDPOINT"], - npm: "@ai-sdk/openai-compatible", - api: "http://localhost:8080/v1", - name: "Privatemode AI", - doc: "https://docs.privatemode.ai/api/overview", - models: { - "gemma-3-27b": { - id: "gemma-3-27b", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-08", - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "whisper-large-v3": { - id: "whisper-large-v3", - name: "Whisper large-v3", - family: "whisper", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2023-09", - release_date: "2023-09-01", - last_updated: "2023-09-01", - modalities: { input: ["audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 0, output: 4096 }, - }, - "qwen3-embedding-4b": { - id: "qwen3-embedding-4b", - name: "Qwen3-Embedding 4B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - structured_output: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-06-06", - last_updated: "2025-06-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32000, output: 2560 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "gpt-oss-120b", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-04", - last_updated: "2025-08-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 128000 }, - }, - "qwen3-coder-30b-a3b": { - id: "qwen3-coder-30b-a3b", - name: "Qwen3-Coder 30B-A3B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04", - last_updated: "2025-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - }, - }, - google: { - id: "google", - env: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"], - npm: "@ai-sdk/google", - name: "Google", - doc: "https://ai.google.dev/gemini-api/docs/models", - models: { - "gemini-flash-lite-latest": { - id: "gemini-flash-lite-latest", - name: "Gemini Flash-Lite Latest", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-pro-preview-05-06": { - id: "gemini-2.5-pro-preview-05-06", - name: "Gemini 2.5 Pro Preview 05-06", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-05-06", - last_updated: "2025-05-06", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-live-2.5-flash-preview-native-audio": { - id: "gemini-live-2.5-flash-preview-native-audio", - name: "Gemini Live 2.5 Flash Preview Native Audio", - family: "gemini-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-09-18", - modalities: { input: ["text", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.5, output: 2, input_audio: 3, output_audio: 12 }, - limit: { context: 131072, output: 65536 }, - }, - "gemini-3.1-pro-preview-customtools": { - id: "gemini-3.1-pro-preview-customtools", - name: "Gemini 3.1 Pro Preview Custom Tools", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-lite-preview-09-2025": { - id: "gemini-2.5-flash-lite-preview-09-2025", - name: "Gemini 2.5 Flash Lite Preview 09-25", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-1.5-flash": { - id: "gemini-1.5-flash", - name: "Gemini 1.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-05-14", - last_updated: "2024-05-14", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3, cache_read: 0.01875 }, - limit: { context: 1000000, output: 8192 }, - }, - "gemini-1.5-pro": { - id: "gemini-1.5-pro", - name: "Gemini 1.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-02-15", - last_updated: "2024-02-15", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 5, cache_read: 0.3125 }, - limit: { context: 1000000, output: 8192 }, - }, - "gemma-3n-e4b-it": { - id: "gemma-3n-e4b-it", - name: "Gemma 3n 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "gemini-3.1-flash-lite-preview": { - id: "gemini-3.1-flash-lite-preview", - name: "Gemini 3.1 Flash Lite Preview", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-03-03", - last_updated: "2026-03-03", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-3.1-pro-preview": { - id: "gemini-3.1-pro-preview", - name: "Gemini 3.1 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-19", - last_updated: "2026-02-19", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.0-flash": { - id: "gemini-2.0-flash", - name: "Gemini 2.0 Flash", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 8192 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 0.5, - output: 3, - cache_read: 0.05, - context_over_200k: { input: 0.5, output: 3, cache_read: 0.05 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-preview-tts": { - id: "gemini-2.5-flash-preview-tts", - name: "Gemini 2.5 Flash Preview TTS", - family: "gemini-flash", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-05-01", - last_updated: "2025-05-01", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - cost: { input: 0.5, output: 10 }, - limit: { context: 8000, output: 16000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-11-18", - last_updated: "2025-11-18", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 2, output: 12, cache_read: 0.2, context_over_200k: { input: 4, output: 18, cache_read: 0.4 } }, - limit: { context: 1000000, output: 64000 }, - }, - "gemini-2.5-flash-preview-05-20": { - id: "gemini-2.5-flash-preview-05-20", - name: "Gemini 2.5 Flash Preview 05-20", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-embedding-001": { - id: "gemini-embedding-001", - name: "Gemini Embedding 001", - family: "gemini", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-05", - release_date: "2025-05-20", - last_updated: "2025-05-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0 }, - limit: { context: 2048, output: 3072 }, - }, - "gemini-2.5-pro": { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { - input: 1.25, - output: 10, - cache_read: 0.125, - context_over_200k: { input: 2.5, output: 15, cache_read: 0.25 }, - }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-flash-latest": { - id: "gemini-flash-latest", - name: "Gemini Flash Latest", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemma-4-31b-it": { - id: "gemma-4-31b-it", - name: "Gemma 4 31B", - family: "gemma", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 256000, output: 8192 }, - }, - "gemini-2.5-pro-preview-06-05": { - id: "gemini-2.5-pro-preview-06-05", - name: "Gemini 2.5 Pro Preview 06-05", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-05", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1.25, output: 10, cache_read: 0.31 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-image": { - id: "gemini-2.5-flash-image", - name: "Gemini 2.5 Flash Image", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.3, output: 30, cache_read: 0.075 }, - limit: { context: 32768, output: 32768 }, - }, - "gemini-2.5-flash-lite-preview-06-17": { - id: "gemini-2.5-flash-lite-preview-06-17", - name: "Gemini 2.5 Flash Lite Preview 06-17", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025, input_audio: 0.3 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemma-3-12b-it": { - id: "gemma-3-12b-it", - name: "Gemma 3 12B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-03-20", - last_updated: "2025-06-05", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.03, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemma-3n-e2b-it": { - id: "gemma-3n-e2b-it", - name: "Gemma 3n 2B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-09", - last_updated: "2025-07-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2000 }, - }, - "gemini-3.1-flash-image-preview": { - id: "gemini-3.1-flash-image-preview", - name: "Gemini 3.1 Flash Image (Preview)", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-01", - release_date: "2026-02-26", - last_updated: "2026-02-26", - modalities: { input: ["text", "image", "pdf"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.25, output: 60 }, - limit: { context: 131072, output: 32768 }, - }, - "gemini-3.1-flash-lite": { - id: "gemini-3.1-flash-lite", - name: "Gemini 3.1 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-05-07", - last_updated: "2026-05-07", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.5, cache_read: 0.025, cache_write: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemma-3-4b-it": { - id: "gemma-3-4b-it", - name: "Gemma 3 4B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-13", - last_updated: "2025-03-13", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 32768, output: 8192 }, - }, - "gemini-2.5-flash-preview-04-17": { - id: "gemini-2.5-flash-preview-04-17", - name: "Gemini 2.5 Flash Preview 04-17", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-04-17", - last_updated: "2025-04-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.15, output: 0.6, cache_read: 0.0375 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-pro-preview-tts": { - id: "gemini-2.5-pro-preview-tts", - name: "Gemini 2.5 Pro Preview TTS", - family: "gemini-flash", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - knowledge: "2025-01", - release_date: "2025-05-01", - last_updated: "2025-05-01", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: false, - cost: { input: 1, output: 20 }, - limit: { context: 8000, output: 16000 }, - }, - "gemini-2.5-flash-preview-09-2025": { - id: "gemini-2.5-flash-preview-09-2025", - name: "Gemini 2.5 Flash Preview 09-25", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-25", - last_updated: "2025-09-25", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.3, output: 2.5, cache_read: 0.075, input_audio: 1 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemma-3-27b-it": { - id: "gemma-3-27b-it", - name: "Gemma 3 27B", - family: "gemma", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-03-12", - last_updated: "2025-03-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 8192 }, - }, - "gemma-4-26b-a4b-it": { - id: "gemma-4-26b-a4b-it", - name: "Gemma 4 26B", - family: "gemma", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - limit: { context: 256000, output: 8192 }, - }, - "gemini-2.5-flash-lite": { - id: "gemini-2.5-flash-lite", - name: "Gemini 2.5 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-06-17", - last_updated: "2025-06-17", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.1, output: 0.4, cache_read: 0.025 }, - limit: { context: 1048576, output: 65536 }, - }, - "gemini-2.5-flash-image-preview": { - id: "gemini-2.5-flash-image-preview", - name: "Gemini 2.5 Flash Image (Preview)", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2025-06", - release_date: "2025-08-26", - last_updated: "2025-08-26", - modalities: { input: ["text", "image"], output: ["text", "image"] }, - open_weights: false, - cost: { input: 0.3, output: 30, cache_read: 0.075 }, - limit: { context: 32768, output: 32768 }, - }, - "gemini-1.5-flash-8b": { - id: "gemini-1.5-flash-8b", - name: "Gemini 1.5 Flash-8B", - family: "gemini-flash", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2024-10-03", - last_updated: "2024-10-03", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.0375, output: 0.15, cache_read: 0.01 }, - limit: { context: 1000000, output: 8192 }, - }, - "gemini-live-2.5-flash": { - id: "gemini-live-2.5-flash", - name: "Gemini Live 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-09-01", - last_updated: "2025-09-01", - modalities: { input: ["text", "image", "audio", "video"], output: ["text", "audio"] }, - open_weights: false, - cost: { input: 0.5, output: 2, input_audio: 3, output_audio: 12 }, - limit: { context: 128000, output: 8000 }, - }, - "gemini-2.0-flash-lite": { - id: "gemini-2.0-flash-lite", - name: "Gemini 2.0 Flash Lite", - family: "gemini-flash-lite", - attachment: true, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2024-06", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.075, output: 0.3 }, - limit: { context: 1048576, output: 8192 }, - }, - }, - }, - drun: { - id: "drun", - env: ["DRUN_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://chat.d.run/v1", - name: "D.Run (China)", - doc: "https://www.d.run", - models: { - "public/deepseek-r1": { - id: "public/deepseek-r1", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.55, output: 2.2 }, - limit: { context: 131072, output: 32000 }, - }, - "public/minimax-m25": { - id: "public/minimax-m25", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_details" }, - temperature: true, - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.29, output: 1.16 }, - limit: { context: 204800, output: 131072 }, - }, - "public/deepseek-v3": { - id: "public/deepseek-v3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2024-12-26", - last_updated: "2024-12-26", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.28, output: 1.1 }, - limit: { context: 131072, output: 8192 }, - }, - }, - }, - moonshotai: { - id: "moonshotai", - env: ["MOONSHOT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.moonshot.ai/v1", - name: "Moonshot AI", - doc: "https://platform.moonshot.ai/docs/api/chat", - models: { - "kimi-k2-0905-preview": { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - family: "kimi-k2.5", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01", - release_date: "2026-01", - last_updated: "2026-01", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3, cache_read: 0.1 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.15, output: 8, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4, cache_read: 0.16 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-turbo-preview": { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-09-05", - last_updated: "2025-09-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.4, output: 10, cache_read: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "kimi-k2-0711-preview": { - id: "kimi-k2-0711-preview", - name: "Kimi K2 0711", - family: "kimi", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-07-14", - last_updated: "2025-07-14", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 131072, output: 16384 }, - }, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - family: "kimi-thinking", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-08", - release_date: "2025-11-06", - last_updated: "2025-11-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.5, cache_read: 0.15 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - berget: { - id: "berget", - env: ["BERGET_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.berget.ai/v1", - name: "Berget.AI", - doc: "https://api.berget.ai", - models: { - "zai-org/GLM-4.7": { - id: "zai-org/GLM-4.7", - name: "GLM 4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.77, output: 2.75 }, - limit: { context: 128000, output: 8192 }, - }, - "mistralai/Mistral-Small-3.2-24B-Instruct-2506": { - id: "mistralai/Mistral-Small-3.2-24B-Instruct-2506", - name: "Mistral Small 3.2 24B Instruct 2506", - family: "mistral-small", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-09", - release_date: "2025-10-01", - last_updated: "2025-10-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.33, output: 0.33 }, - limit: { context: 32000, output: 8192 }, - }, - "mistralai/Mistral-Medium-3.5-128B": { - id: "mistralai/Mistral-Medium-3.5-128B", - name: "Mistral Medium 3.5 128B", - family: "mistral-medium", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2026-04", - release_date: "2026-04-29", - last_updated: "2026-04-29", - modalities: { input: ["image", "text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.65, output: 5.5 }, - limit: { context: 262144, output: 131072 }, - }, - "meta-llama/Llama-3.3-70B-Instruct": { - id: "meta-llama/Llama-3.3-70B-Instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2023-12", - release_date: "2025-04-27", - last_updated: "2025-04-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.99, output: 0.99 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT-OSS-120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.44, output: 0.99 }, - limit: { context: 128000, output: 8192 }, - }, - "google/gemma-4-31B-it": { - id: "google/gemma-4-31B-it", - name: "Gemma 4 31B Instruct", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-12", - release_date: "2026-04-02", - last_updated: "2026-04-02", - modalities: { input: ["audio", "image", "text", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.275, output: 0.55 }, - limit: { context: 128000, output: 8192 }, - }, - }, - }, - "github-models": { - id: "github-models", - env: ["GITHUB_TOKEN"], - npm: "@ai-sdk/openai-compatible", - api: "https://models.github.ai/inference", - name: "GitHub Models", - doc: "https://docs.github.com/en/github-models", - models: { - "deepseek/deepseek-v3-0324": { - id: "deepseek/deepseek-v3-0324", - name: "DeepSeek-V3-0324", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-03-24", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "deepseek/deepseek-r1": { - id: "deepseek/deepseek-r1", - name: "DeepSeek-R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 65536, output: 8192 }, - }, - "deepseek/deepseek-r1-0528": { - id: "deepseek/deepseek-r1-0528", - name: "DeepSeek-R1-0528", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-05-28", - last_updated: "2025-05-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 65536, output: 8192 }, - }, - "ai21-labs/ai21-jamba-1.5-mini": { - id: "ai21-labs/ai21-jamba-1.5-mini", - name: "AI21 Jamba 1.5 Mini", - family: "jamba", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-08-29", - last_updated: "2024-08-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 4096 }, - }, - "ai21-labs/ai21-jamba-1.5-large": { - id: "ai21-labs/ai21-jamba-1.5-large", - name: "AI21 Jamba 1.5 Large", - family: "jamba", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-08-29", - last_updated: "2024-08-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 256000, output: 4096 }, - }, - "microsoft/phi-3.5-mini-instruct": { - id: "microsoft/phi-3.5-mini-instruct", - name: "Phi-3.5-mini instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-medium-4k-instruct": { - id: "microsoft/phi-3-medium-4k-instruct", - name: "Phi-3-medium instruct (4k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 4096, output: 1024 }, - }, - "microsoft/phi-3.5-moe-instruct": { - id: "microsoft/phi-3.5-moe-instruct", - name: "Phi-3.5-MoE instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-mini-128k-instruct": { - id: "microsoft/phi-3-mini-128k-instruct", - name: "Phi-3-mini instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-4-mini-instruct": { - id: "microsoft/phi-4-mini-instruct", - name: "Phi-4-mini-instruct", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-4-reasoning": { - id: "microsoft/phi-4-reasoning", - name: "Phi-4-Reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-small-8k-instruct": { - id: "microsoft/phi-3-small-8k-instruct", - name: "Phi-3-small instruct (8k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2048 }, - }, - "microsoft/phi-3.5-vision-instruct": { - id: "microsoft/phi-3.5-vision-instruct", - name: "Phi-3.5-vision instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-08-20", - last_updated: "2024-08-20", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-mini-4k-instruct": { - id: "microsoft/phi-3-mini-4k-instruct", - name: "Phi-3-mini instruct (4k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 4096, output: 1024 }, - }, - "microsoft/phi-4-mini-reasoning": { - id: "microsoft/phi-4-mini-reasoning", - name: "Phi-4-mini-reasoning", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-small-128k-instruct": { - id: "microsoft/phi-3-small-128k-instruct", - name: "Phi-3-small instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-3-medium-128k-instruct": { - id: "microsoft/phi-3-medium-128k-instruct", - name: "Phi-3-medium instruct (128k)", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-04-23", - last_updated: "2024-04-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/phi-4": { - id: "microsoft/phi-4", - name: "Phi-4", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 16000, output: 4096 }, - }, - "microsoft/phi-4-multimodal-instruct": { - id: "microsoft/phi-4-multimodal-instruct", - name: "Phi-4-multimodal-instruct", - family: "phi", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-12-11", - last_updated: "2024-12-11", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "microsoft/mai-ds-r1": { - id: "microsoft/mai-ds-r1", - name: "MAI-DS-R1", - family: "mai", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-06", - release_date: "2025-01-20", - last_updated: "2025-01-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 65536, output: 8192 }, - }, - "cohere/cohere-command-r-08-2024": { - id: "cohere/cohere-command-r-08-2024", - name: "Cohere Command R 08-2024", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-08-01", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cohere/cohere-command-a": { - id: "cohere/cohere-command-a", - name: "Cohere Command A", - family: "command-a", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cohere/cohere-command-r-plus": { - id: "cohere/cohere-command-r-plus", - name: "Cohere Command R+", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-04-04", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cohere/cohere-command-r": { - id: "cohere/cohere-command-r", - name: "Cohere Command R", - family: "command-r", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-03-11", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "cohere/cohere-command-r-plus-08-2024": { - id: "cohere/cohere-command-r-plus-08-2024", - name: "Cohere Command R+ 08-2024", - family: "command-r", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-08-01", - last_updated: "2024-08-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 4096 }, - }, - "xai/grok-3-mini": { - id: "xai/grok-3-mini", - name: "Grok 3 Mini", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-09", - last_updated: "2024-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "xai/grok-3": { - id: "xai/grok-3", - name: "Grok 3", - family: "grok", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2024-12-09", - last_updated: "2024-12-09", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "openai/o1-mini": { - id: "openai/o1-mini", - name: "OpenAI o1-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2023-10", - release_date: "2024-09-12", - last_updated: "2024-12-17", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 65536 }, - }, - "openai/gpt-4o-mini": { - id: "openai/gpt-4o-mini", - name: "GPT-4o mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o4-mini": { - id: "openai/o4-mini", - name: "OpenAI o4-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2024-04", - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o1-preview": { - id: "openai/o1-preview", - name: "OpenAI o1-preview", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2023-10", - release_date: "2024-09-12", - last_updated: "2024-09-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "openai/o1": { - id: "openai/o1", - name: "OpenAI o1", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2023-10", - release_date: "2024-09-12", - last_updated: "2024-12-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/o3-mini": { - id: "openai/o3-mini", - name: "OpenAI o3-mini", - family: "o-mini", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2024-04", - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4.1-nano": { - id: "openai/gpt-4.1-nano", - name: "GPT-4.1-nano", - family: "gpt-nano", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/o3": { - id: "openai/o3", - name: "OpenAI o3", - family: "o", - attachment: false, - reasoning: true, - tool_call: false, - temperature: false, - knowledge: "2024-04", - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 200000, output: 100000 }, - }, - "openai/gpt-4o": { - id: "openai/gpt-4o", - name: "GPT-4o", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-10", - release_date: "2024-05-13", - last_updated: "2024-05-13", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4.1": { - id: "openai/gpt-4.1", - name: "GPT-4.1", - family: "gpt", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "openai/gpt-4.1-mini": { - id: "openai/gpt-4.1-mini", - name: "GPT-4.1-mini", - family: "gpt-mini", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04", - release_date: "2025-04-14", - last_updated: "2025-04-14", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 16384 }, - }, - "meta/llama-4-scout-17b-16e-instruct": { - id: "meta/llama-4-scout-17b-16e-instruct", - name: "Llama 4 Scout 17B 16E Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/meta-llama-3.1-8b-instruct": { - id: "meta/meta-llama-3.1-8b-instruct", - name: "Meta-Llama-3.1-8B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "meta/llama-3.3-70b-instruct": { - id: "meta/llama-3.3-70b-instruct", - name: "Llama-3.3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "meta/meta-llama-3-70b-instruct": { - id: "meta/meta-llama-3-70b-instruct", - name: "Meta-Llama-3-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2048 }, - }, - "meta/llama-3.2-90b-vision-instruct": { - id: "meta/llama-3.2-90b-vision-instruct", - name: "Llama-3.2-90B-Vision-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/llama-3.2-11b-vision-instruct": { - id: "meta/llama-3.2-11b-vision-instruct", - name: "Llama-3.2-11B-Vision-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-09-25", - last_updated: "2024-09-25", - modalities: { input: ["text", "image", "audio"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "meta/meta-llama-3.1-405b-instruct": { - id: "meta/meta-llama-3.1-405b-instruct", - name: "Meta-Llama-3.1-405B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "meta/meta-llama-3.1-70b-instruct": { - id: "meta/meta-llama-3.1-70b-instruct", - name: "Meta-Llama-3.1-70B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-07-23", - last_updated: "2024-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "meta/meta-llama-3-8b-instruct": { - id: "meta/meta-llama-3-8b-instruct", - name: "Meta-Llama-3-8B-Instruct", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-04-18", - last_updated: "2024-04-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2048 }, - }, - "meta/llama-4-maverick-17b-128e-instruct-fp8": { - id: "meta/llama-4-maverick-17b-128e-instruct-fp8", - name: "Llama 4 Maverick 17B 128E Instruct FP8", - family: "llama", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-12", - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "core42/jais-30b-chat": { - id: "core42/jais-30b-chat", - name: "JAIS 30b Chat", - family: "jais", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2023-03", - release_date: "2023-08-30", - last_updated: "2023-08-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 2048 }, - }, - "mistral-ai/mistral-nemo": { - id: "mistral-ai/mistral-nemo", - name: "Mistral Nemo", - family: "mistral-nemo", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-07-18", - last_updated: "2024-07-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "mistral-ai/ministral-3b": { - id: "mistral-ai/ministral-3b", - name: "Ministral 3B", - family: "ministral", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 8192 }, - }, - "mistral-ai/mistral-large-2411": { - id: "mistral-ai/mistral-large-2411", - name: "Mistral Large 24.11", - family: "mistral-large", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2024-11-01", - last_updated: "2024-11-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral-ai/mistral-small-2503": { - id: "mistral-ai/mistral-small-2503", - name: "Mistral Small 3.1", - family: "mistral-small", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-03-01", - last_updated: "2025-03-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral-ai/mistral-medium-2505": { - id: "mistral-ai/mistral-medium-2505", - name: "Mistral Medium 3 (25.05)", - family: "mistral-medium", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09", - release_date: "2025-05-01", - last_updated: "2025-05-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 128000, output: 32768 }, - }, - "mistral-ai/codestral-2501": { - id: "mistral-ai/codestral-2501", - name: "Codestral 25.01", - family: "codestral", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-03", - release_date: "2025-01-01", - last_updated: "2025-01-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 32000, output: 8192 }, - }, - }, - }, - neuralwatt: { - id: "neuralwatt", - env: ["NEURALWATT_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.neuralwatt.com/v1", - name: "Neuralwatt", - doc: "https://portal.neuralwatt.com/docs", - models: { - "glm-5-fast": { - id: "glm-5-fast", - name: "GLM 5 Fast", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.1, output: 3.6 }, - limit: { context: 200000, output: 200000 }, - }, - "kimi-k2.6-fast": { - id: "kimi-k2.6-fast", - name: "Kimi K2.6 Fast", - family: "kimi", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.69, output: 3.22 }, - limit: { context: 262144, output: 262144 }, - }, - "qwen3.5-397b-fast": { - id: "qwen3.5-397b-fast", - name: "Qwen3.5 397B Fast", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.69, output: 4.14 }, - limit: { context: 262144, output: 262144 }, - }, - "glm-5.1-fast": { - id: "glm-5.1-fast", - name: "GLM 5.1 Fast", - family: "glm", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.1, output: 3.6 }, - limit: { context: 200000, output: 200000 }, - }, - "qwen3.6-35b-fast": { - id: "qwen3.6-35b-fast", - name: "Qwen3.6 35B Fast", - family: "qwen3.6", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.1 }, - limit: { context: 131072, output: 131072 }, - }, - "kimi-k2.5-fast": { - id: "kimi-k2.5-fast", - name: "Kimi K2.5 Fast", - family: "kimi", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.52, output: 2.59 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3.5-397B-A17B-FP8": { - id: "Qwen/Qwen3.5-397B-A17B-FP8", - name: "Qwen3.5 397B A17B FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.69, output: 4.14 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3.6-35B-A3B": { - id: "Qwen/Qwen3.6-35B-A3B", - name: "Qwen3.6 35B A3B", - family: "qwen3.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.05, output: 0.1 }, - limit: { context: 131072, output: 131072 }, - }, - "zai-org/GLM-5.1-FP8": { - id: "zai-org/GLM-5.1-FP8", - name: "GLM 5.1 FP8", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.1, output: 3.6 }, - limit: { context: 200000, output: 200000 }, - }, - "mistralai/Devstral-Small-2-24B-Instruct-2512": { - id: "mistralai/Devstral-Small-2-24B-Instruct-2512", - name: "Devstral Small 2 24B Instruct 2512", - family: "devstral", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-12-09", - last_updated: "2025-12-09", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.35 }, - limit: { context: 262144, output: 262144 }, - }, - "openai/gpt-oss-20b": { - id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.03, output: 0.16 }, - limit: { context: 16384, output: 16384 }, - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "Kimi K2.6", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.69, output: 3.22 }, - limit: { context: 262144, output: 262144 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.52, output: 2.59 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.35, output: 1.38 }, - limit: { context: 196608, output: 196608 }, - }, - }, - }, - togetherai: { - id: "togetherai", - env: ["TOGETHER_API_KEY"], - npm: "@ai-sdk/togetherai", - name: "Together AI", - doc: "https://docs.together.ai/docs/serverless-models", - models: { - "essentialai/Rnj-1-Instruct": { - id: "essentialai/Rnj-1-Instruct", - name: "Rnj-1 Instruct", - family: "rnj", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12-05", - last_updated: "2025-12-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.15 }, - limit: { context: 32768, output: 32768 }, - }, - "Qwen/Qwen3.5-397B-A17B": { - id: "Qwen/Qwen3.5-397B-A17B", - name: "Qwen3.5 397B A17B", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-16", - last_updated: "2026-02-16", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 3.6 }, - limit: { context: 262144, output: 130000 }, - }, - "Qwen/Qwen3.6-Plus": { - id: "Qwen/Qwen3.6-Plus", - name: "Qwen3.6 Plus", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-30", - last_updated: "2026-04-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 3 }, - limit: { context: 1000000, output: 500000 }, - }, - "Qwen/Qwen3-Coder-Next-FP8": { - id: "Qwen/Qwen3-Coder-Next-FP8", - name: "Qwen3 Coder Next FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2026-02-03", - release_date: "2026-02-03", - last_updated: "2026-02-03", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 1.2 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507-tput": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507-tput", - name: "Qwen3 235B A22B Instruct 2507 FP8", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.6 }, - limit: { context: 262144, output: 262144 }, - }, - "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8": { - id: "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", - name: "Qwen3 Coder 480B A35B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-23", - last_updated: "2025-07-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2, output: 2 }, - limit: { context: 262144, output: 262144 }, - }, - "zai-org/GLM-5.1": { - id: "zai-org/GLM-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-11", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.4, output: 4.4 }, - limit: { context: 202752, output: 131072 }, - }, - "meta-llama/Llama-3.3-70B-Instruct-Turbo": { - id: "meta-llama/Llama-3.3-70B-Instruct-Turbo", - name: "Llama 3.3 70B", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-12", - release_date: "2024-12-06", - last_updated: "2024-12-06", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.88, output: 0.88 }, - limit: { context: 131072, output: 131072 }, - }, - "deepseek-ai/DeepSeek-V3": { - id: "deepseek-ai/DeepSeek-V3", - name: "DeepSeek V3", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-07", - release_date: "2025-01-20", - last_updated: "2025-05-29", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1.25, output: 1.25 }, - limit: { context: 131072, output: 131072 }, - }, - "deepseek-ai/DeepSeek-R1": { - id: "deepseek-ai/DeepSeek-R1", - name: "DeepSeek R1", - family: "deepseek-thinking", - attachment: false, - reasoning: true, - tool_call: false, - temperature: true, - knowledge: "2024-07", - release_date: "2024-12-26", - last_updated: "2025-03-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 3, output: 7 }, - limit: { context: 163839, output: 163839 }, - }, - "deepseek-ai/DeepSeek-V3-1": { - id: "deepseek-ai/DeepSeek-V3-1", - name: "DeepSeek V3.1", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-21", - last_updated: "2025-08-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.7 }, - limit: { context: 131072, output: 131072 }, - }, - "deepseek-ai/DeepSeek-V4-Pro": { - id: "deepseek-ai/DeepSeek-V4-Pro", - name: "DeepSeek V4 Pro", - family: "deepseek", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-24", - last_updated: "2026-04-24", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 2.1, output: 4.4, cache_read: 0.2 }, - limit: { context: 512000, output: 384000 }, - }, - "openai/gpt-oss-120b": { - id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 131072, output: 131072 }, - }, - "google/gemma-4-31B-it": { - id: "google/gemma-4-31B-it", - name: "Gemma 4 31B Instruct", - family: "gemma", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-07", - last_updated: "2026-04-07", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.5 }, - limit: { context: 262144, output: 131072 }, - }, - "moonshotai/Kimi-K2.6": { - id: "moonshotai/Kimi-K2.6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 1.2, output: 4.5, cache_read: 0.2 }, - limit: { context: 262144, output: 131000 }, - }, - "moonshotai/Kimi-K2.5": { - id: "moonshotai/Kimi-K2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: true, - temperature: true, - knowledge: "2026-01", - release_date: "2026-01-27", - last_updated: "2026-01-27", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.5, output: 2.8 }, - limit: { context: 262144, output: 262144 }, - }, - "MiniMaxAI/MiniMax-M2.5": { - id: "MiniMaxAI/MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMaxAI/MiniMax-M2.7": { - id: "MiniMaxAI/MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06 }, - limit: { context: 202752, output: 131072 }, - }, - }, - }, - "qihang-ai": { - id: "qihang-ai", - env: ["QIHANG_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.qhaigc.net/v1", - name: "QiHang", - doc: "https://www.qhaigc.net/docs", - models: { - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.71, output: 3.57 }, - limit: { context: 200000, output: 32000 }, - }, - "gemini-3-flash-preview": { - id: "gemini-3-flash-preview", - name: "Gemini 3 Flash Preview", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.07, output: 0.43, context_over_200k: { input: 0.07, output: 0.43 } }, - limit: { context: 1048576, output: 65536 }, - }, - "gpt-5-mini": { - id: "gpt-5-mini", - name: "GPT-5-Mini", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-09-30", - release_date: "2025-09-15", - last_updated: "2025-09-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.04, output: 0.29 }, - limit: { context: 200000, output: 64000 }, - }, - "gemini-3-pro-preview": { - id: "gemini-3-pro-preview", - name: "Gemini 3 Pro Preview", - family: "gemini-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-11", - release_date: "2025-11-19", - last_updated: "2025-11-19", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.57, output: 3.43 }, - limit: { context: 1000000, output: 65000 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.43, output: 2.14 }, - limit: { context: 200000, output: 64000 }, - }, - "gpt-5.2": { - id: "gpt-5.2", - name: "GPT-5.2", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 2 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gpt-5.2-codex": { - id: "gpt-5.2-codex", - name: "GPT-5.2 Codex", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2025-12-11", - last_updated: "2025-12-11", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 1.14 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "gemini-2.5-flash": { - id: "gemini-2.5-flash", - name: "Gemini 2.5 Flash", - family: "gemini-flash", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2025-12-17", - last_updated: "2025-12-17", - modalities: { input: ["text", "image", "video", "audio", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.09, output: 0.71, context_over_200k: { input: 0.09, output: 0.71 } }, - limit: { context: 1048576, output: 65536 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-10-01", - last_updated: "2025-10-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.14, output: 0.71 }, - limit: { context: 200000, output: 64000 }, - }, - }, - }, - "tencent-tokenhub": { - id: "tencent-tokenhub", - env: ["TENCENT_TOKENHUB_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://tokenhub.tencentmaas.com/v1", - name: "Tencent TokenHub", - doc: "https://cloud.tencent.com/document/product/1823/130050", - models: { - "hy3-preview": { - id: "hy3-preview", - name: "Hy3 preview", - family: "Hy", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-04-20", - last_updated: "2026-04-20", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 256000, output: 64000 }, - }, - }, - }, - anthropic: { - id: "anthropic", - env: ["ANTHROPIC_API_KEY"], - npm: "@ai-sdk/anthropic", - name: "Anthropic", - doc: "https://docs.anthropic.com/en/docs/about-claude/models", - models: { - "claude-3-sonnet-20240229": { - id: "claude-3-sonnet-20240229", - name: "Claude Sonnet 3", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-04", - last_updated: "2024-03-04", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "claude-haiku-4-5": { - id: "claude-haiku-4-5", - name: "Claude Haiku 4.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-5-20251101": { - id: "claude-opus-4-5-20251101", - name: "Claude Opus 4.5", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-01", - last_updated: "2025-11-01", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-3-opus-20240229": { - id: "claude-3-opus-20240229", - name: "Claude Opus 3", - family: "claude-opus", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-02-29", - last_updated: "2024-02-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 4096 }, - }, - "claude-3-5-haiku-20241022": { - id: "claude-3-5-haiku-20241022", - name: "Claude Haiku 3.5", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-3-5-sonnet-20241022": { - id: "claude-3-5-sonnet-20241022", - name: "Claude Sonnet 3.5 v2", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-sonnet-4-6": { - id: "claude-sonnet-4-6", - name: "Claude Sonnet 4.6", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 1000000, output: 64000 }, - }, - "claude-opus-4-0": { - id: "claude-opus-4-0", - name: "Claude Opus 4 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-opus-4-7": { - id: "claude-opus-4-7", - name: "Claude Opus 4.7", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - }, - "claude-3-haiku-20240307": { - id: "claude-3-haiku-20240307", - name: "Claude Haiku 3", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2023-08-31", - release_date: "2024-03-13", - last_updated: "2024-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.25, output: 1.25, cache_read: 0.03, cache_write: 0.3 }, - limit: { context: 200000, output: 4096 }, - }, - "claude-sonnet-4-5-20250929": { - id: "claude-sonnet-4-5-20250929", - name: "Claude Sonnet 4.5", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-3-5-haiku-latest": { - id: "claude-3-5-haiku-latest", - name: "Claude Haiku 3.5 (latest)", - family: "claude-haiku", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-07-31", - release_date: "2024-10-22", - last_updated: "2024-10-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-opus-4-1": { - id: "claude-opus-4-1", - name: "Claude Opus 4.1 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-sonnet-4-0": { - id: "claude-sonnet-4-0", - name: "Claude Sonnet 4 (latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-3-5-sonnet-20240620": { - id: "claude-3-5-sonnet-20240620", - name: "Claude Sonnet 3.5", - family: "claude-sonnet", - attachment: true, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2024-04-30", - release_date: "2024-06-20", - last_updated: "2024-06-20", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 8192 }, - }, - "claude-opus-4-5": { - id: "claude-opus-4-5", - name: "Claude Opus 4.5 (latest)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-11-24", - last_updated: "2025-11-24", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-1-20250805": { - id: "claude-opus-4-1-20250805", - name: "Claude Opus 4.1", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - "claude-haiku-4-5-20251001": { - id: "claude-haiku-4-5-20251001", - name: "Claude Haiku 4.5", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2025-10-15", - last_updated: "2025-10-15", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-sonnet-4-20250514": { - id: "claude-sonnet-4-20250514", - name: "Claude Sonnet 4", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-03-13", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 }, - limit: { context: 1000000, output: 128000 }, - experimental: { - modes: { - fast: { - cost: { input: 30, output: 150, cache_read: 3, cache_write: 37.5 }, - provider: { body: { speed: "fast" }, headers: { "anthropic-beta": "fast-mode-2026-02-01" } }, - }, - }, - }, - }, - "claude-3-7-sonnet-20250219": { - id: "claude-3-7-sonnet-20250219", - name: "Claude Sonnet 3.7", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10-31", - release_date: "2025-02-19", - last_updated: "2025-02-19", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-sonnet-4-5": { - id: "claude-sonnet-4-5", - name: "Claude Sonnet 4.5 (latest)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2025-09-29", - last_updated: "2025-09-29", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, - limit: { context: 200000, output: 64000 }, - }, - "claude-opus-4-20250514": { - id: "claude-opus-4-20250514", - name: "Claude Opus 4", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2025-05-22", - last_updated: "2025-05-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 }, - limit: { context: 200000, output: 32000 }, - }, - }, - }, - modelscope: { - id: "modelscope", - env: ["MODELSCOPE_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api-inference.modelscope.cn/v1", - name: "ModelScope", - doc: "https://modelscope.cn/docs/model-service/API-Inference/intro", - models: { - "Qwen/Qwen3-30B-A3B-Thinking-2507": { - id: "Qwen/Qwen3-30B-A3B-Thinking-2507", - name: "Qwen3 30B A3B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 32768 }, - }, - "Qwen/Qwen3-30B-A3B-Instruct-2507": { - id: "Qwen/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-30", - last_updated: "2025-07-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 16384 }, - }, - "Qwen/Qwen3-235B-A22B-Instruct-2507": { - id: "Qwen/Qwen3-235B-A22B-Instruct-2507", - name: "Qwen3 235B A22B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-04-28", - last_updated: "2025-07-21", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "Qwen/Qwen3-Coder-30B-A3B-Instruct": { - id: "Qwen/Qwen3-Coder-30B-A3B-Instruct", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-31", - last_updated: "2025-07-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "Qwen/Qwen3-235B-A22B-Thinking-2507": { - id: "Qwen/Qwen3-235B-A22B-Thinking-2507", - name: "Qwen3-235B-A22B-Thinking-2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-25", - last_updated: "2025-07-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "ZhipuAI/GLM-4.5": { - id: "ZhipuAI/GLM-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "ZhipuAI/GLM-4.6": { - id: "ZhipuAI/GLM-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 202752, output: 98304 }, - }, - }, - }, - "hpc-ai": { - id: "hpc-ai", - env: ["HPC_AI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.hpc-ai.com/inference/v1", - name: "HPC-AI", - doc: "https://www.hpc-ai.com/doc/docs/quickstart/", - models: { - "zai-org/glm-5.1": { - id: "zai-org/glm-5.1", - name: "GLM 5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-04-08", - last_updated: "2026-04-08", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.66, output: 2, cache_read: 0.12 }, - limit: { context: 202000, output: 202000 }, - }, - "minimax/minimax-m2.5": { - id: "minimax/minimax-m2.5", - name: "MiniMax M2.5", - family: "minimax-m2.5", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: false, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-03-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.14, output: 0.56, cache_read: 0.014 }, - limit: { context: 1000000, output: 131072 }, - }, - "moonshotai/kimi-k2.5": { - id: "moonshotai/kimi-k2.5", - name: "Kimi K2.5", - family: "kimi", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: false, - knowledge: "2025-01-01", - release_date: "2026-01-01", - last_updated: "2026-03-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.21, output: 1, cache_read: 0.03 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - gitlab: { - id: "gitlab", - env: ["GITLAB_TOKEN"], - npm: "gitlab-ai-provider", - name: "GitLab Duo", - doc: "https://docs.gitlab.com/user/duo_agent_platform/", - models: { - "duo-chat-gpt-5-4-nano": { - id: "duo-chat-gpt-5-4-nano", - name: "Agentic Chat (GPT-5.4 Nano)", - family: "gpt-nano", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-gpt-5-mini": { - id: "duo-chat-gpt-5-mini", - name: "Agentic Chat (GPT-5 Mini)", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-05-30", - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-sonnet-4-6": { - id: "duo-chat-sonnet-4-6", - name: "Agentic Chat (Claude Sonnet 4.6)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-08-31", - release_date: "2026-02-17", - last_updated: "2026-02-17", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 64000 }, - }, - "duo-chat-gpt-5-2": { - id: "duo-chat-gpt-5-2", - name: "Agentic Chat (GPT-5.2)", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-23", - last_updated: "2026-01-23", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-gpt-5-codex": { - id: "duo-chat-gpt-5-codex", - name: "Agentic Chat (GPT-5 Codex)", - family: "gpt-codex", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-gpt-5-1": { - id: "duo-chat-gpt-5-1", - name: "Agentic Chat (GPT-5.1)", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2024-09-30", - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-gpt-5-2-codex": { - id: "duo-chat-gpt-5-2-codex", - name: "Agentic Chat (GPT-5.2 Codex)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-01-22", - last_updated: "2026-01-22", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-sonnet-4-5": { - id: "duo-chat-sonnet-4-5", - name: "Agentic Chat (Claude Sonnet 4.5)", - family: "claude-sonnet", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-07-31", - release_date: "2026-01-08", - last_updated: "2026-01-08", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 64000 }, - }, - "duo-chat-gpt-5-4": { - id: "duo-chat-gpt-5-4", - name: "Agentic Chat (GPT-5.4)", - family: "gpt", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-05", - last_updated: "2026-03-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 1050000, input: 922000, output: 128000 }, - }, - "duo-chat-haiku-4-5": { - id: "duo-chat-haiku-4-5", - name: "Agentic Chat (Claude Haiku 4.5)", - family: "claude-haiku", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-02-28", - release_date: "2026-01-08", - last_updated: "2026-01-08", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 64000 }, - }, - "duo-chat-gpt-5-3-codex": { - id: "duo-chat-gpt-5-3-codex", - name: "Agentic Chat (GPT-5.3 Codex)", - family: "gpt-codex", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-gpt-5-4-mini": { - id: "duo-chat-gpt-5-4-mini", - name: "Agentic Chat (GPT-5.4 Mini)", - family: "gpt-mini", - attachment: true, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: false, - knowledge: "2025-08-31", - release_date: "2026-03-17", - last_updated: "2026-03-17", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0 }, - limit: { context: 400000, input: 272000, output: 128000 }, - }, - "duo-chat-opus-4-7": { - id: "duo-chat-opus-4-7", - name: "Agentic Chat (Claude Opus 4.7)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: false, - knowledge: "2026-01-31", - release_date: "2026-04-16", - last_updated: "2026-04-16", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 64000 }, - }, - "duo-chat-opus-4-5": { - id: "duo-chat-opus-4-5", - name: "Agentic Chat (Claude Opus 4.5)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-03-31", - release_date: "2026-01-08", - last_updated: "2026-01-08", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 64000 }, - }, - "duo-chat-opus-4-6": { - id: "duo-chat-opus-4-6", - name: "Agentic Chat (Claude Opus 4.6)", - family: "claude-opus", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-05-31", - release_date: "2026-02-05", - last_updated: "2026-02-05", - modalities: { input: ["text", "image", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 1000000, output: 64000 }, - }, - }, - }, - xiaomi: { - id: "xiaomi", - env: ["XIAOMI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.xiaomimimo.com/v1", - name: "Xiaomi", - doc: "https://platform.xiaomimimo.com/#/docs", - models: { - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0.4, output: 2, cache_read: 0.08 }, - limit: { context: 262144, output: 131072 }, - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { - input: 0.4, - output: 2, - cache_read: 0.08, - context_over_200k: { input: 0.8, output: 4, cache_read: 0.16 }, - }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 3, cache_read: 0.2, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.3, cache_read: 0.01 }, - limit: { context: 262144, output: 65536 }, - }, - }, - }, - clarifai: { - id: "clarifai", - env: ["CLARIFAI_PAT"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.clarifai.com/v2/ext/openai/v1", - name: "Clarifai", - doc: "https://docs.clarifai.com/compute/inference/", - models: { - "arcee_ai/AFM/models/trinity-mini": { - id: "arcee_ai/AFM/models/trinity-mini", - name: "Trinity Mini", - family: "trinity-mini", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2024-10", - release_date: "2025-12", - last_updated: "2026-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.045, output: 0.15 }, - limit: { context: 131072, output: 131072 }, - }, - "mistralai/completion/models/Ministral-3-14B-Reasoning-2512": { - id: "mistralai/completion/models/Ministral-3-14B-Reasoning-2512", - name: "Ministral 3 14B Reasoning 2512", - family: "ministral", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-12", - release_date: "2025-12-01", - last_updated: "2025-12-12", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 2.5, output: 1.7 }, - limit: { context: 262144, output: 262144 }, - }, - "mistralai/completion/models/Ministral-3-3B-Reasoning-2512": { - id: "mistralai/completion/models/Ministral-3-3B-Reasoning-2512", - name: "Ministral 3 3B Reasoning 2512", - family: "ministral", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12", - last_updated: "2026-02-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 1.039, output: 0.54825 }, - limit: { context: 262144, output: 262144 }, - }, - "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR": { - id: "deepseek-ai/deepseek-ocr/models/DeepSeek-OCR", - name: "DeepSeek OCR", - family: "deepseek", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-10-20", - last_updated: "2026-02-25", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 0.7 }, - limit: { context: 8192, output: 8192 }, - }, - "openai/chat-completion/models/gpt-oss-20b": { - id: "openai/chat-completion/models/gpt-oss-20b", - name: "GPT OSS 20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-12-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.045, output: 0.18 }, - limit: { context: 131072, output: 16384 }, - }, - "openai/chat-completion/models/gpt-oss-120b-high-throughput": { - id: "openai/chat-completion/models/gpt-oss-120b-high-throughput", - name: "GPT OSS 120B High Throughput", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2026-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.09, output: 0.36 }, - limit: { context: 131072, output: 16384 }, - }, - "minimaxai/chat-completion/models/MiniMax-M2_5-high-throughput": { - id: "minimaxai/chat-completion/models/MiniMax-M2_5-high-throughput", - name: "MiniMax-M2.5 High Throughput", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "qwen/qwenCoder/models/Qwen3-Coder-30B-A3B-Instruct": { - id: "qwen/qwenCoder/models/Qwen3-Coder-30B-A3B-Instruct", - name: "Qwen3 Coder 30B A3B Instruct", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-31", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.11458, output: 0.74812 }, - limit: { context: 262144, output: 65536 }, - }, - "qwen/qwenLM/models/Qwen3-30B-A3B-Thinking-2507": { - id: "qwen/qwenLM/models/Qwen3-30B-A3B-Thinking-2507", - name: "Qwen3 30B A3B Thinking 2507", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-31", - last_updated: "2026-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.36, output: 1.3 }, - limit: { context: 262144, output: 131072 }, - }, - "qwen/qwenLM/models/Qwen3-30B-A3B-Instruct-2507": { - id: "qwen/qwenLM/models/Qwen3-30B-A3B-Instruct-2507", - name: "Qwen3 30B A3B Instruct 2507", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: true, - structured_output: true, - temperature: true, - release_date: "2025-07-30", - last_updated: "2026-02-25", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.5 }, - limit: { context: 262144, output: 262144 }, - }, - "clarifai/main/models/mm-poly-8b": { - id: "clarifai/main/models/mm-poly-8b", - name: "MM Poly 8B", - family: "mm-poly", - attachment: true, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2025-06", - last_updated: "2026-02-25", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: false, - cost: { input: 0.658, output: 1.11 }, - limit: { context: 32768, output: 4096 }, - }, - "moonshotai/chat-completion/models/Kimi-K2_6": { - id: "moonshotai/chat-completion/models/Kimi-K2_6", - name: "Kimi K2.6", - family: "kimi-k2.6", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - knowledge: "2025-01", - release_date: "2026-04-21", - last_updated: "2026-04-21", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.95, output: 4 }, - limit: { context: 262144, output: 262144 }, - }, - }, - }, - "minimax-cn": { - id: "minimax-cn", - env: ["MINIMAX_API_KEY"], - npm: "@ai-sdk/anthropic", - api: "https://api.minimaxi.com/anthropic/v1", - name: "MiniMax (minimaxi.com)", - doc: "https://platform.minimaxi.com/docs/guides/quickstart", - models: { - "MiniMax-M2": { - id: "MiniMax-M2", - name: "MiniMax-M2", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-10-27", - last_updated: "2025-10-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 196608, output: 128000 }, - }, - "MiniMax-M2.5": { - id: "MiniMax-M2.5", - name: "MiniMax-M2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-12", - last_updated: "2026-02-12", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.03, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7": { - id: "MiniMax-M2.7", - name: "MiniMax-M2.7", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.7-highspeed": { - id: "MiniMax-M2.7-highspeed", - name: "MiniMax-M2.7-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.1": { - id: "MiniMax-M2.1", - name: "MiniMax-M2.1", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-23", - last_updated: "2025-12-23", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 204800, output: 131072 }, - }, - "MiniMax-M2.5-highspeed": { - id: "MiniMax-M2.5-highspeed", - name: "MiniMax-M2.5-highspeed", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-13", - last_updated: "2026-02-13", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.4, cache_read: 0.06, cache_write: 0.375 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - "regolo-ai": { - id: "regolo-ai", - env: ["REGOLO_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.regolo.ai/v1", - name: "Regolo AI", - doc: "https://docs.regolo.ai/", - models: { - "mistral-small3.2": { - id: "mistral-small3.2", - name: "Mistral Small 3.2", - family: "mistral-small", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-01-31", - last_updated: "2025-01-31", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.5, output: 2.2 }, - limit: { context: 120000, output: 120000 }, - }, - "qwen3-embedding-8b": { - id: "qwen3-embedding-8b", - name: "Qwen3-Embedding-8B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.1, output: 0.1 }, - limit: { context: 32768, output: 8192 }, - }, - "llama-3.3-70b-instruct": { - id: "llama-3.3-70b-instruct", - name: "Llama 3.3 70B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-28", - last_updated: "2025-04-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.6, output: 2.7 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3-reranker-4b": { - id: "qwen3-reranker-4b", - name: "Qwen3-Reranker-4B", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: false, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.12, output: 0.12 }, - limit: { context: 32768, output: 8192 }, - }, - "mistral-small-4-119b": { - id: "mistral-small-4-119b", - name: "Mistral Small 4 119B", - family: "mistral-small", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-15", - last_updated: "2026-03-15", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: false, - cost: { input: 0.75, output: 3 }, - limit: { context: 256000, output: 16384 }, - }, - "qwen3.5-122b": { - id: "qwen3.5-122b", - name: "Qwen3.5-122B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.9, output: 3.6 }, - limit: { context: 262144, output: 16384 }, - }, - "qwen-image": { - id: "qwen-image", - name: "Qwen-Image", - family: "qwen", - attachment: false, - reasoning: false, - tool_call: false, - temperature: true, - release_date: "2026-03-01", - last_updated: "2026-03-01", - modalities: { input: ["text"], output: ["image"] }, - open_weights: false, - cost: { input: 0.5, output: 2 }, - limit: { context: 8192, output: 4096 }, - }, - "qwen3-coder-next": { - id: "qwen3-coder-next", - name: "Qwen3-Coder-Next", - family: "qwen", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-01", - last_updated: "2026-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 1.2 }, - limit: { context: 262144, output: 16384 }, - }, - "minimax-m2.5": { - id: "minimax-m2.5", - name: "MiniMax 2.5", - family: "minimax", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-10", - last_updated: "2026-03-10", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.8, output: 3.5 }, - limit: { context: 190000, output: 64000 }, - }, - "gpt-oss-20b": { - id: "gpt-oss-20b", - name: "GPT-OSS-20B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-03-01", - last_updated: "2026-03-01", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.4, output: 1.8 }, - limit: { context: 128000, output: 16384 }, - }, - "qwen3.5-9b": { - id: "qwen3.5-9b", - name: "Qwen3.5-9B", - family: "qwen", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2026-02-01", - last_updated: "2026-02-01", - modalities: { input: ["text", "image"], output: ["text"] }, - open_weights: true, - cost: { input: 0.15, output: 0.6 }, - limit: { context: 262144, output: 8192 }, - }, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT-OSS-120B", - family: "gpt-oss", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-08-05", - last_updated: "2025-08-05", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 1, output: 4.2 }, - limit: { context: 128000, output: 16384 }, - }, - "llama-3.1-8b-instruct": { - id: "llama-3.1-8b-instruct", - name: "Llama 3.1 8B Instruct", - family: "llama", - attachment: false, - reasoning: false, - tool_call: true, - temperature: true, - release_date: "2025-04-07", - last_updated: "2025-04-07", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0.05, output: 0.25 }, - limit: { context: 120000, output: 120000 }, - }, - }, - }, - "xiaomi-token-plan-ams": { - id: "xiaomi-token-plan-ams", - env: ["XIAOMI_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://token-plan-ams.xiaomimimo.com/v1", - name: "Xiaomi Token Plan (Europe)", - doc: "https://platform.xiaomimimo.com/#/docs", - models: { - "mimo-v2-tts": { - id: "mimo-v2-tts", - name: "MiMo-V2-TTS", - family: "mimo", - attachment: false, - reasoning: false, - tool_call: false, - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["audio"] }, - open_weights: true, - cost: { input: 0, output: 0 }, - limit: { context: 8192, output: 16384 }, - }, - "mimo-v2-flash": { - id: "mimo-v2-flash", - name: "MiMo-V2-Flash", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12-01", - release_date: "2025-12-16", - last_updated: "2026-02-04", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 65536 }, - }, - "mimo-v2-pro": { - id: "mimo-v2-pro", - name: "MiMo-V2-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 2, output: 6, cache_read: 0.4 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2.5": { - id: "mimo-v2.5", - name: "MiMo-V2.5", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text", "image", "audio", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - "mimo-v2-omni": { - id: "mimo-v2-omni", - name: "MiMo-V2-Omni", - family: "mimo", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-03-18", - last_updated: "2026-03-18", - modalities: { input: ["text", "image", "audio", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, cache_read: 0 }, - limit: { context: 262144, output: 131072 }, - }, - "mimo-v2.5-pro": { - id: "mimo-v2.5-pro", - name: "MiMo-V2.5-Pro", - family: "mimo", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2024-12", - release_date: "2026-04-22", - last_updated: "2026-04-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, context_over_200k: { input: 0, output: 0, cache_read: 0 } }, - limit: { context: 1048576, output: 131072 }, - }, - }, - }, - zhipuai: { - id: "zhipuai", - env: ["ZHIPU_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://open.bigmodel.cn/api/paas/v4", - name: "Zhipu AI", - doc: "https://docs.z.ai/guides/overview/pricing", - models: { - "glm-5v-turbo": { - id: "glm-5v-turbo", - name: "GLM-5V-Turbo", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-04-01", - last_updated: "2026-04-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 5, output: 22, cache_read: 1.2, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-5": { - id: "glm-5", - name: "GLM-5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - release_date: "2026-02-11", - last_updated: "2026-02-11", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 1, output: 3.2, cache_read: 0.2, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-5.1": { - id: "glm-5.1", - name: "GLM-5.1", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - structured_output: true, - temperature: true, - release_date: "2026-03-27", - last_updated: "2026-03-27", - modalities: { input: ["text"], output: ["text"] }, - open_weights: false, - cost: { input: 6, output: 24, cache_read: 1.3, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.7-flash": { - id: "glm-4.7-flash", - name: "GLM-4.7-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.5-flash": { - id: "glm-4.5-flash", - name: "GLM-4.5-Flash", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0, output: 0, cache_read: 0, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.6v": { - id: "glm-4.6v", - name: "GLM-4.6V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-08", - last_updated: "2025-12-08", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.3, output: 0.9 }, - limit: { context: 128000, output: 32768 }, - }, - "glm-4.6": { - id: "glm-4.6", - name: "GLM-4.6", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-09-30", - last_updated: "2025-09-30", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - "glm-4.5v": { - id: "glm-4.5v", - name: "GLM-4.5V", - family: "glm", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-08-11", - last_updated: "2025-08-11", - modalities: { input: ["text", "image", "video"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 1.8 }, - limit: { context: 64000, output: 16384 }, - }, - "glm-4.5-air": { - id: "glm-4.5-air", - name: "GLM-4.5-Air", - family: "glm-air", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.2, output: 1.1, cache_read: 0.03, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.5": { - id: "glm-4.5", - name: "GLM-4.5", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2025-07-28", - last_updated: "2025-07-28", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 131072, output: 98304 }, - }, - "glm-4.7-flashx": { - id: "glm-4.7-flashx", - name: "GLM-4.7-FlashX", - family: "glm-flash", - attachment: false, - reasoning: true, - tool_call: true, - temperature: true, - knowledge: "2025-04", - release_date: "2026-01-19", - last_updated: "2026-01-19", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.07, output: 0.4, cache_read: 0.01, cache_write: 0 }, - limit: { context: 200000, output: 131072 }, - }, - "glm-4.7": { - id: "glm-4.7", - name: "GLM-4.7", - family: "glm", - attachment: false, - reasoning: true, - tool_call: true, - interleaved: { field: "reasoning_content" }, - temperature: true, - knowledge: "2025-04", - release_date: "2025-12-22", - last_updated: "2025-12-22", - modalities: { input: ["text"], output: ["text"] }, - open_weights: true, - cost: { input: 0.6, output: 2.2, cache_read: 0.11, cache_write: 0 }, - limit: { context: 204800, output: 131072 }, - }, - }, - }, - nova: { - id: "nova", - env: ["NOVA_API_KEY"], - npm: "@ai-sdk/openai-compatible", - api: "https://api.nova.amazon.com/v1", - name: "Nova", - doc: "https://nova.amazon.com/dev/documentation", - models: { - "nova-2-lite-v1": { - id: "nova-2-lite-v1", - name: "Nova 2 Lite", - family: "nova-lite", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-01", - last_updated: "2025-12-01", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, reasoning: 0 }, - limit: { context: 1000000, output: 64000 }, - }, - "nova-2-pro-v1": { - id: "nova-2-pro-v1", - name: "Nova 2 Pro", - family: "nova-pro", - attachment: true, - reasoning: true, - tool_call: true, - temperature: true, - release_date: "2025-12-03", - last_updated: "2026-01-03", - modalities: { input: ["text", "image", "video", "pdf"], output: ["text"] }, - open_weights: false, - cost: { input: 0, output: 0, reasoning: 0 }, - limit: { context: 1000000, output: 64000 }, - }, - }, - }, -} diff --git a/packages/core/src/permission.ts b/packages/core/src/permission.ts new file mode 100644 index 0000000000..ec8038f713 --- /dev/null +++ b/packages/core/src/permission.ts @@ -0,0 +1,45 @@ +export * as PermissionV2 from "./permission" + +import { Schema } from "effect" +import { Wildcard } from "./util/wildcard" + +export const Action = Schema.Literals(["allow", "deny", "ask"]).annotate({ identifier: "PermissionV2.Action" }) +export type Action = typeof Action.Type + +export const Rule = Schema.Struct({ + permission: Schema.String, + pattern: Schema.String, + action: Action, +}).annotate({ identifier: "PermissionV2.Rule" }) +export type Rule = typeof Rule.Type + +export const Ruleset = Schema.Array(Rule).annotate({ identifier: "PermissionV2.Ruleset" }) +export type Ruleset = typeof Ruleset.Type + +const EDIT_TOOLS = ["edit", "write", "apply_patch"] + +export function evaluate(permission: string, pattern: string, ...rulesets: Ruleset[]): Rule { + return ( + rulesets + .flat() + .findLast((rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern)) ?? { + action: "ask", + permission, + pattern: "*", + } + ) +} + +export function merge(...rulesets: Ruleset[]): Ruleset { + return rulesets.flat() +} + +export function disabled(tools: string[], ruleset: Ruleset): Set { + return new Set( + tools.filter((tool) => { + const permission = EDIT_TOOLS.includes(tool) ? "edit" : tool + const rule = ruleset.findLast((rule) => Wildcard.match(permission, rule.permission)) + return rule?.pattern === "*" && rule.action === "deny" + }), + ) +} diff --git a/packages/core/src/plugin.ts b/packages/core/src/plugin.ts index dfcae94685..ab2d4cbf7d 100644 --- a/packages/core/src/plugin.ts +++ b/packages/core/src/plugin.ts @@ -2,27 +2,26 @@ export * as PluginV2 from "./plugin" import { createDraft, finishDraft, type Draft } from "immer" import type { LanguageModelV3 } from "@ai-sdk/provider" -import { type ProviderV2 } from "./provider" -import { Context, Effect, Layer, Schema } from "effect" +import { Context, Effect, Exit, Layer, PubSub, Schema, Scope, Stream } from "effect" import type { ModelV2 } from "./model" +import type { AgentV2 } from "./agent" +import type { Catalog } from "./catalog" export const ID = Schema.String.pipe(Schema.brand("Plugin.ID")) export type ID = typeof ID.Type type HookSpec = { - "provider.update": { - input: {} - output: { - provider: ProviderV2.Info - cancel: boolean - } + "catalog.transform": { + input: Catalog.Context + output: {} } - "model.update": { - input: {} - output: { - model: ModelV2.Info - cancel: boolean + "account.switched": { + input: { + serviceID: import("./account").AccountV2.ServiceID + from?: import("./account").AccountV2.ID + to?: import("./account").AccountV2.ID } + output: {} } "aisdk.language": { input: { @@ -44,6 +43,27 @@ type HookSpec = { sdk?: any } } + "agent.update": { + input: {} + output: { + agent: AgentV2.Info + cancel: boolean + } + } + "agent.remove": { + input: { + agent: AgentV2.Info + } + output: { + cancel: boolean + } + } + "agent.default": { + input: {} + output: { + agent?: AgentV2.ID + } + } } export type Hooks = { @@ -61,15 +81,25 @@ export type HookFunctions = { export type HookInput = HookSpec[Name]["input"] export type HookOutput = HookSpec[Name]["output"] -export type Effect = Effect.Effect +export type Effect = Effect.Effect export function define(input: { id: ID; effect: Effect.Effect }) { return input } export interface Interface { - readonly add: (input: { id: ID; effect: Effect }) => Effect.Effect + readonly add: (input: { + id: ID + effect: Effect.Effect + }) => Effect.Effect readonly remove: (id: ID) => Effect.Effect + readonly added: () => Stream.Stream + readonly triggerFor: ( + id: ID, + name: Name, + input: HookInput, + output: HookOutput, + ) => Effect.Effect & HookOutput> readonly trigger: ( name: Name, input: HookInput, @@ -85,21 +115,33 @@ export const layer = Layer.effect( let hooks: { id: ID hooks: HookFunctions + scope: Scope.Closeable }[] = [] + const added = yield* PubSub.unbounded() + + yield* Effect.addFinalizer(() => PubSub.shutdown(added)) const svc = Service.of({ add: Effect.fn("Plugin.add")(function* (input) { - const result = yield* input.effect - if (!result) return + const existing = hooks.find((item) => item.id === input.id) + if (existing) yield* Scope.close(existing.scope, Exit.void).pipe(Effect.ignore) + const scope = yield* Scope.make() + const result = yield* input.effect.pipe(Scope.provide(scope)) hooks = [ ...hooks.filter((item) => item.id !== input.id), { id: input.id, - hooks: result, + hooks: result ?? {}, + scope, }, ] + yield* PubSub.publish(added, input.id) }), + added: () => Stream.fromPubSub(added), trigger: Effect.fn("Plugin.trigger")(function* (name, input, output) { + return yield* svc.triggerFor(ID.make("*"), name, input, output) + }), + triggerFor: Effect.fn("Plugin.triggerFor")(function* (id, name, input, output) { const draftEntries = new Map>() const event = { ...input, @@ -114,6 +156,7 @@ export const layer = Layer.effect( } for (const item of hooks) { + if (id !== ID.make("*") && item.id !== id) continue const match = item.hooks[name] if (!match) continue yield* match(event as any).pipe( @@ -133,7 +176,9 @@ export const layer = Layer.effect( return event as any }), remove: Effect.fn("Plugin.remove")(function* (id) { + const existing = hooks.find((item) => item.id === id) hooks = hooks.filter((item) => item.id !== id) + if (existing) yield* Scope.close(existing.scope, Exit.void).pipe(Effect.ignore) }), }) return svc diff --git a/packages/core/src/plugin/account.ts b/packages/core/src/plugin/account.ts new file mode 100644 index 0000000000..d4d00c3ab6 --- /dev/null +++ b/packages/core/src/plugin/account.ts @@ -0,0 +1,41 @@ +import { Effect, Scope, Stream } from "effect" +import { AccountV2 } from "../account" +import { EventV2 } from "../event" +import { PluginV2 } from "../plugin" + +export const AccountPlugin = PluginV2.define({ + id: PluginV2.ID.make("account"), + effect: Effect.gen(function* () { + const accounts = yield* AccountV2.Service + const events = yield* EventV2.Service + const scope = yield* Scope.Scope + + yield* events.subscribe(AccountV2.Event.Switched).pipe( + Stream.runForEach((event) => + PluginV2.Service.use((plugin) => plugin.trigger("account.switched", event.data, {})).pipe(Effect.asVoid), + ), + Effect.forkIn(scope, { startImmediately: true }), + ) + + return { + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + const account = yield* accounts.active(AccountV2.ServiceID.make(item.provider.id)).pipe(Effect.orDie) + if (!account) continue + evt.provider.update(item.provider.id, (provider) => { + provider.enabled = { + via: "account", + service: account.serviceID, + } + if (account.credential.type === "api") { + provider.options.aisdk.provider.apiKey = account.credential.key + Object.assign(provider.options.aisdk.provider, account.credential.metadata ?? {}) + } + if (account.credential.type === "oauth") provider.options.aisdk.provider.apiKey = account.credential.access + }) + } + }), + "account.switched": Effect.fn(function* () {}), + } + }), +}) diff --git a/packages/core/src/plugin/auth.ts b/packages/core/src/plugin/auth.ts deleted file mode 100644 index 81cbfbe3f7..0000000000 --- a/packages/core/src/plugin/auth.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Effect } from "effect" -import { AuthV2 } from "../auth" -import { PluginV2 } from "../plugin" - -export const AuthPlugin = PluginV2.define({ - id: PluginV2.ID.make("auth"), - effect: Effect.gen(function* () { - const auth = yield* AuthV2.Service - return { - "provider.update": Effect.fn(function* (evt) { - const account = yield* auth.active(AuthV2.ServiceID.make(evt.provider.id)).pipe(Effect.orDie) - if (!account) return - evt.provider.enabled = { - via: "auth", - service: account.serviceID, - } - if (account.credential.type === "api") { - evt.provider.options.aisdk.provider.apiKey = account.credential.key - Object.assign(evt.provider.options.aisdk.provider, account.credential.metadata ?? {}) - } - if (account.credential.type === "oauth") { - evt.provider.options.aisdk.provider.apiKey = account.credential.access - } - }), - } - }), -}) diff --git a/packages/core/src/plugin/boot.ts b/packages/core/src/plugin/boot.ts index 74560ac85b..5624369e04 100644 --- a/packages/core/src/plugin/boot.ts +++ b/packages/core/src/plugin/boot.ts @@ -1,18 +1,22 @@ export * as PluginBoot from "./boot" import { Context, Deferred, Effect, Layer } from "effect" -import { AuthV2 } from "../auth" +import { AccountV2 } from "../account" +import { AgentV2 } from "../agent" import { Catalog } from "../catalog" +import { EventV2 } from "../event" import { Npm } from "../npm" import { PluginV2 } from "../plugin" -import { AuthPlugin } from "./auth" +import { AccountPlugin } from "./account" import { EnvPlugin } from "./env" import { ModelsDevPlugin } from "./models-dev" import { ProviderPlugins } from "./provider" type Plugin = { id: PluginV2.ID - effect: Effect.Effect + effect: PluginV2.Effect< + Catalog.Service | AgentV2.Service | AccountV2.Service | Npm.Service | EventV2.Service | PluginV2.Service + > } export interface Interface { @@ -21,51 +25,57 @@ export interface Interface { export class Service extends Context.Service()("@opencode/v2/PluginBoot") {} -export const layer: Layer.Layer = - Layer.effect( - Service, - Effect.gen(function* () { - const catalog = yield* Catalog.Service - const plugin = yield* PluginV2.Service - const auth = yield* AuthV2.Service - const npm = yield* Npm.Service - const done = yield* Deferred.make() +export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const agent = yield* AgentV2.Service + const catalog = yield* Catalog.Service + const plugin = yield* PluginV2.Service + const accounts = yield* AccountV2.Service + const npm = yield* Npm.Service + const events = yield* EventV2.Service + const done = yield* Deferred.make() - const add = Effect.fn("PluginBoot.add")(function* (input: Plugin) { - yield* plugin.add({ - id: input.id, - effect: input.effect.pipe( - Effect.provideService(Catalog.Service, catalog), - Effect.provideService(AuthV2.Service, auth), - Effect.provideService(Npm.Service, npm), - ), - }) + const add = Effect.fn("PluginBoot.add")(function* (input: Plugin) { + yield* plugin.add({ + id: input.id, + effect: input.effect.pipe( + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(AgentV2.Service, agent), + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Npm.Service, npm), + Effect.provideService(EventV2.Service, events), + Effect.provideService(PluginV2.Service, plugin), + ), }) + }) - const boot = Effect.gen(function* () { - yield* add(EnvPlugin) - yield* add(AuthPlugin) - for (const item of ProviderPlugins) { - yield* add(item) - } - yield* add(ModelsDevPlugin) - }).pipe(Effect.withSpan("PluginBoot.boot")) + const boot = Effect.gen(function* () { + yield* add(EnvPlugin) + yield* add(AccountPlugin) + for (const item of ProviderPlugins) { + yield* add(item) + } + yield* add(ModelsDevPlugin) + }).pipe(Effect.withSpan("PluginBoot.boot")) - yield* boot.pipe( - Effect.exit, - Effect.flatMap((exit) => Deferred.done(done, exit)), - Effect.forkScoped, - ) + yield* boot.pipe( + Effect.exit, + Effect.flatMap((exit) => Deferred.done(done, exit)), + Effect.forkScoped, + ) - return Service.of({ - wait: () => Deferred.await(done), - }) - }), - ) + return Service.of({ + wait: () => Deferred.await(done), + }) + }), +) export const defaultLayer = layer.pipe( + Layer.provide(AgentV2.defaultLayer), Layer.provide(Catalog.defaultLayer), + Layer.provide(EventV2.defaultLayer), Layer.provide(PluginV2.defaultLayer), - Layer.provide(Layer.orDie(AuthV2.defaultLayer)), + Layer.provide(AccountV2.defaultLayer), Layer.provide(Npm.defaultLayer), ) diff --git a/packages/core/src/plugin/env.ts b/packages/core/src/plugin/env.ts index d63936fa13..3d716fe6f3 100644 --- a/packages/core/src/plugin/env.ts +++ b/packages/core/src/plugin/env.ts @@ -5,12 +5,16 @@ export const EnvPlugin = PluginV2.define({ id: PluginV2.ID.make("env"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - const key = evt.provider.env.find((item) => process.env[item]) - if (!key) return - evt.provider.enabled = { - via: "env", - name: key, + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + const key = item.provider.env.find((env) => process.env[env]) + if (!key) continue + evt.provider.update(item.provider.id, (provider) => { + provider.enabled = { + via: "env", + name: key, + } + }) } }), } diff --git a/packages/core/src/plugin/models-dev.ts b/packages/core/src/plugin/models-dev.ts index e67c2e75a9..bde162d729 100644 --- a/packages/core/src/plugin/models-dev.ts +++ b/packages/core/src/plugin/models-dev.ts @@ -1,7 +1,8 @@ -import { DateTime, Effect } from "effect" +import { DateTime, Effect, Scope, Stream } from "effect" import { Catalog } from "../catalog" +import { EventV2 } from "../event" import { ModelV2 } from "../model" -import { ModelsDev } from "../models" +import { ModelsDev } from "../models-dev" import { PluginV2 } from "../plugin" import { ProviderV2 } from "../provider" @@ -54,55 +55,66 @@ export const ModelsDevPlugin = PluginV2.define({ effect: Effect.gen(function* () { const catalog = yield* Catalog.Service const modelsDev = yield* ModelsDev.Service - for (const item of Object.values(yield* modelsDev.get())) { - const providerID = ProviderV2.ID.make(item.id) - yield* catalog.provider.update(providerID, (provider) => { - provider.name = item.name - provider.env = [...item.env] - provider.endpoint = item.npm - ? { - type: "aisdk", - package: item.npm, - url: item.api, - } - : { - type: "unknown", - } - }) - - for (const model of Object.values(item.models)) { - const modelID = ModelV2.ID.make(model.id) - yield* catalog.model - .update(providerID, modelID, (draft) => { - draft.name = model.name - draft.family = model.family ? ModelV2.Family.make(model.family) : undefined - draft.endpoint = model.provider?.npm + const events = yield* EventV2.Service + const scope = yield* Scope.Scope + const load = yield* catalog.loader() + const refresh = Effect.fn("ModelsDevPlugin.refresh")(function* () { + const data = yield* modelsDev.get() + yield* load((catalog) => { + for (const item of Object.values(data)) { + const providerID = ProviderV2.ID.make(item.id) + catalog.provider.update(providerID, (provider) => { + provider.name = item.name + provider.env = [...item.env] + provider.endpoint = item.npm ? { type: "aisdk", - package: model.provider?.npm, - url: model.provider.api, + package: item.npm, + url: item.api, } : { type: "unknown", } - draft.capabilities = { - tools: model.tool_call, - input: [...(model.modalities?.input ?? [])], - output: [...(model.modalities?.output ?? [])], - } - draft.variants = variants(model) - draft.time.released = released(model.release_date) - draft.cost = cost(model.cost) - draft.status = model.status ?? "active" - draft.enabled = true - draft.limit = { - context: model.limit.context, - input: model.limit.input, - output: model.limit.output, - } }) - .pipe(Effect.orDie) - } - } + + for (const model of Object.values(item.models)) { + const modelID = ModelV2.ID.make(model.id) + catalog.model.update(providerID, modelID, (draft) => { + draft.name = model.name + draft.family = model.family ? ModelV2.Family.make(model.family) : undefined + draft.endpoint = model.provider?.npm + ? { + type: "aisdk", + package: model.provider?.npm, + url: model.provider.api, + } + : { + type: "unknown", + } + draft.capabilities = { + tools: model.tool_call, + input: [...(model.modalities?.input ?? [])], + output: [...(model.modalities?.output ?? [])], + } + draft.variants = variants(model) + draft.time.released = released(model.release_date) + draft.cost = cost(model.cost) + draft.status = model.status ?? "active" + draft.enabled = true + draft.limit = { + context: model.limit.context, + input: model.limit.input, + output: model.limit.output, + } + }) + } + } + }) + }) + yield* refresh() + yield* events.subscribe(ModelsDev.Event.Refreshed).pipe( + Stream.runForEach(() => refresh()), + Effect.forkIn(scope, { startImmediately: true }), + ) }).pipe(Effect.provide(ModelsDev.defaultLayer)), }) diff --git a/packages/core/src/plugin/provider/amazon-bedrock.ts b/packages/core/src/plugin/provider/amazon-bedrock.ts index 366548a0a3..44a5d44e2b 100644 --- a/packages/core/src/plugin/provider/amazon-bedrock.ts +++ b/packages/core/src/plugin/provider/amazon-bedrock.ts @@ -50,14 +50,19 @@ export const AmazonBedrockPlugin = PluginV2.define({ id: PluginV2.ID.make("amazon-bedrock"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.amazonBedrock) return - if (evt.provider.endpoint.type !== "aisdk") return - if (typeof evt.provider.options.aisdk.provider.endpoint !== "string") return - // The AI SDK expects a base URL, but users configure Bedrock private/VPC - // endpoints as `endpoint`; move it into the catalog endpoint URL once. - evt.provider.endpoint.url = evt.provider.options.aisdk.provider.endpoint - delete evt.provider.options.aisdk.provider.endpoint + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/amazon-bedrock") continue + evt.provider.update(item.provider.id, (provider) => { + if (provider.endpoint.type !== "aisdk") return + if (typeof provider.options.aisdk.provider.endpoint !== "string") return + // The AI SDK expects a base URL, but users configure Bedrock private/VPC + // endpoints as `endpoint`; move it into the catalog endpoint URL once. + provider.endpoint.url = provider.options.aisdk.provider.endpoint + delete provider.options.aisdk.provider.endpoint + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/amazon-bedrock") return diff --git a/packages/core/src/plugin/provider/anthropic.ts b/packages/core/src/plugin/provider/anthropic.ts index 14851c4a31..99fbf56ab3 100644 --- a/packages/core/src/plugin/provider/anthropic.ts +++ b/packages/core/src/plugin/provider/anthropic.ts @@ -1,15 +1,19 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const AnthropicPlugin = PluginV2.define({ id: PluginV2.ID.make("anthropic"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.anthropic) return - evt.provider.options.headers["anthropic-beta"] = - "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/anthropic") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["anthropic-beta"] = + "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14" + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/anthropic") return diff --git a/packages/core/src/plugin/provider/azure.ts b/packages/core/src/plugin/provider/azure.ts index 6c29a16103..ea5c34d7c0 100644 --- a/packages/core/src/plugin/provider/azure.ts +++ b/packages/core/src/plugin/provider/azure.ts @@ -14,12 +14,18 @@ export const AzurePlugin = PluginV2.define({ id: PluginV2.ID.make("azure"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.azure) return - const configured = evt.provider.options.aisdk.provider.resourceName - const resourceName = - typeof configured === "string" && configured.trim() !== "" ? configured : process.env.AZURE_RESOURCE_NAME - if (resourceName) evt.provider.options.aisdk.provider.resourceName = resourceName + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/azure") continue + const configured = item.provider.options.aisdk.provider.resourceName + const resourceName = + typeof configured === "string" && configured.trim() !== "" ? configured : process.env.AZURE_RESOURCE_NAME + if (!resourceName) continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.aisdk.provider.resourceName = resourceName + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/azure") return @@ -49,11 +55,17 @@ export const AzureCognitiveServicesPlugin = PluginV2.define({ id: PluginV2.ID.make("azure-cognitive-services"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("azure-cognitive-services")) return + "catalog.transform": Effect.fn(function* (evt) { const resourceName = process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME - if (resourceName) - evt.provider.options.aisdk.provider.baseURL = `https://${resourceName}.cognitiveservices.azure.com/openai` + if (!resourceName) return + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai-compatible") continue + if (!item.provider.id.includes("azure-cognitive-services")) continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.aisdk.provider.baseURL = `https://${resourceName}.cognitiveservices.azure.com/openai` + }) + } }), "aisdk.language": Effect.fn(function* (evt) { if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return diff --git a/packages/core/src/plugin/provider/cerebras.ts b/packages/core/src/plugin/provider/cerebras.ts index b2fadd8bf1..12da385920 100644 --- a/packages/core/src/plugin/provider/cerebras.ts +++ b/packages/core/src/plugin/provider/cerebras.ts @@ -1,14 +1,18 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const CerebrasPlugin = PluginV2.define({ id: PluginV2.ID.make("cerebras"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("cerebras")) return - evt.provider.options.headers["X-Cerebras-3rd-Party-Integration"] = "opencode" + "catalog.transform": Effect.fn(function* (ctx) { + for (const item of ctx.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/cerebras") continue + ctx.provider.update(item.provider.id, (provider) => { + provider.options.headers["X-Cerebras-3rd-Party-Integration"] = "opencode" + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/cerebras") return diff --git a/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts b/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts index ffcd4adcf4..1cd974ee95 100644 --- a/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts +++ b/packages/core/src/plugin/provider/cloudflare-ai-gateway.ts @@ -45,7 +45,7 @@ const decodeJson = Schema.decodeUnknownOption(Schema.UnknownFromJsonString) function gatewayConfig(options: Record): GatewayConfig | undefined { const accountId = process.env.CLOUDFLARE_ACCOUNT_ID ?? stringOption(options, "accountId") - // AuthPlugin copies CLI prompt metadata into options. The prompt stores the + // AccountPlugin copies CLI prompt metadata into options. The prompt stores the // gateway as gatewayId, while older config examples may use gateway. const gatewayId = process.env.CLOUDFLARE_GATEWAY_ID ?? stringOption(options, "gatewayId") ?? stringOption(options, "gateway") diff --git a/packages/core/src/plugin/provider/cloudflare-workers-ai.ts b/packages/core/src/plugin/provider/cloudflare-workers-ai.ts index f39869b57d..d10f8e79e4 100644 --- a/packages/core/src/plugin/provider/cloudflare-workers-ai.ts +++ b/packages/core/src/plugin/provider/cloudflare-workers-ai.ts @@ -10,13 +10,15 @@ export const CloudflareWorkersAIPlugin = PluginV2.define({ id: PluginV2.ID.make("cloudflare-workers-ai"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== providerID) return - if (evt.provider.endpoint.type !== "aisdk") return - if (evt.provider.endpoint.url) return - - const accountId = resolveAccountId(evt.provider.options.aisdk.provider) - if (accountId) evt.provider.endpoint.url = workersEndpoint(accountId) + "catalog.transform": Effect.fn(function* (evt) { + const item = evt.data.find((record) => record.provider.id === providerID) + if (!item) return + evt.provider.update(item.provider.id, (provider) => { + if (provider.endpoint.type !== "aisdk") return + if (provider.endpoint.url) return + const accountId = resolveAccountId(provider.options.aisdk.provider) + if (accountId) provider.endpoint.url = workersEndpoint(accountId) + }) }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.model.providerID !== providerID) return diff --git a/packages/core/src/plugin/provider/github-copilot.ts b/packages/core/src/plugin/provider/github-copilot.ts index 31e57ba12a..dc984cdef9 100644 --- a/packages/core/src/plugin/provider/github-copilot.ts +++ b/packages/core/src/plugin/provider/github-copilot.ts @@ -15,9 +15,6 @@ export const GithubCopilotPlugin = PluginV2.define({ id: PluginV2.ID.make("github-copilot"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.githubCopilot) return - }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/github-copilot") return const mod = yield* Effect.promise(() => import("../../github-copilot/copilot-provider")) @@ -33,11 +30,14 @@ export const GithubCopilotPlugin = PluginV2.define({ ? evt.sdk.responses(evt.model.apiID) : evt.sdk.chat(evt.model.apiID) }), - "model.update": Effect.fn(function* (evt) { - if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return - // This chat-only alias conflicts with the Copilot GPT-5 Responses route, - // so hide it only for Copilot rather than for every provider catalog. - if (evt.model.id === ModelV2.ID.make("gpt-5-chat-latest")) evt.cancel = true + "catalog.transform": Effect.fn(function* (evt) { + const item = evt.data.find((record) => record.provider.id === ProviderV2.ID.githubCopilot) + if (!item || !item.models.has(ModelV2.ID.make("gpt-5-chat-latest"))) return + evt.model.update(item.provider.id, ModelV2.ID.make("gpt-5-chat-latest"), (model) => { + // This chat-only alias conflicts with the Copilot GPT-5 Responses route, + // so hide it only for Copilot rather than for every provider catalog. + model.enabled = false + }) }), } }), diff --git a/packages/core/src/plugin/provider/google-vertex.ts b/packages/core/src/plugin/provider/google-vertex.ts index 0c335df931..3da7caf4e7 100644 --- a/packages/core/src/plugin/provider/google-vertex.ts +++ b/packages/core/src/plugin/provider/google-vertex.ts @@ -25,7 +25,8 @@ function resolveLocation(options: Record) { } function vertexEndpoint(location: string) { - return location === "global" ? "aiplatform.googleapis.com" : `${location}-aiplatform.googleapis.com` + if (location === "global") return "aiplatform.googleapis.com" + return `${location}-aiplatform.googleapis.com` } function replaceVertexVars(value: string, project: string | undefined, location: string) { @@ -57,20 +58,26 @@ export const GoogleVertexPlugin = PluginV2.define({ id: PluginV2.ID.make("google-vertex"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.googleVertex) return - const project = resolveProject(evt.provider.options.aisdk.provider) - const location = String(resolveLocation(evt.provider.options.aisdk.provider)) - if (project) evt.provider.options.aisdk.provider.project = project - evt.provider.options.aisdk.provider.location = location - if (evt.provider.endpoint.type === "aisdk" && evt.provider.endpoint.url) { - evt.provider.endpoint.url = replaceVertexVars(evt.provider.endpoint.url, project, location) - } - if ( - evt.provider.endpoint.type === "aisdk" && - evt.provider.endpoint.package.includes("@ai-sdk/openai-compatible") - ) { - evt.provider.options.aisdk.provider.fetch = authFetch(evt.provider.options.aisdk.provider.fetch) + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if ( + item.provider.endpoint.package !== "@ai-sdk/google-vertex" && + !item.provider.endpoint.package.includes("@ai-sdk/openai-compatible") + ) + continue + const project = resolveProject(item.provider.options.aisdk.provider) + const location = String(resolveLocation(item.provider.options.aisdk.provider)) + evt.provider.update(item.provider.id, (provider) => { + if (project) provider.options.aisdk.provider.project = project + provider.options.aisdk.provider.location = location + if (provider.endpoint.type === "aisdk" && provider.endpoint.url) { + provider.endpoint.url = replaceVertexVars(provider.endpoint.url, project, location) + } + if (provider.endpoint.type === "aisdk" && provider.endpoint.package.includes("@ai-sdk/openai-compatible")) { + provider.options.aisdk.provider.fetch = authFetch(provider.options.aisdk.provider.fetch) + } + }) } }), "aisdk.sdk": Effect.fn(function* (evt) { @@ -102,34 +109,48 @@ export const GoogleVertexAnthropicPlugin = PluginV2.define({ id: PluginV2.ID.make("google-vertex-anthropic"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("google-vertex-anthropic")) return - const project = - evt.provider.options.aisdk.provider.project ?? - process.env.GOOGLE_CLOUD_PROJECT ?? - process.env.GCP_PROJECT ?? - process.env.GCLOUD_PROJECT - const location = - evt.provider.options.aisdk.provider.location ?? - process.env.GOOGLE_CLOUD_LOCATION ?? - process.env.VERTEX_LOCATION ?? - "global" - if (project) evt.provider.options.aisdk.provider.project = project - evt.provider.options.aisdk.provider.location = location + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/google-vertex/anthropic") continue + const project = + item.provider.options.aisdk.provider.project ?? + process.env.GOOGLE_CLOUD_PROJECT ?? + process.env.GCP_PROJECT ?? + process.env.GCLOUD_PROJECT + const location = + item.provider.options.aisdk.provider.location ?? + process.env.GOOGLE_CLOUD_LOCATION ?? + process.env.VERTEX_LOCATION ?? + "global" + evt.provider.update(item.provider.id, (provider) => { + if (project) provider.options.aisdk.provider.project = project + provider.options.aisdk.provider.location = location + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/google-vertex/anthropic") return const mod = yield* Effect.promise(() => import("@ai-sdk/google-vertex/anthropic")) + const project = + typeof evt.options.project === "string" + ? evt.options.project + : (process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GCP_PROJECT ?? process.env.GCLOUD_PROJECT) + const location = + typeof evt.options.location === "string" + ? evt.options.location + : (process.env.GOOGLE_CLOUD_LOCATION ?? process.env.VERTEX_LOCATION ?? "global") evt.sdk = mod.createVertexAnthropic({ ...evt.options, - project: - typeof evt.options.project === "string" - ? evt.options.project - : (process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GCP_PROJECT ?? process.env.GCLOUD_PROJECT), - location: - typeof evt.options.location === "string" - ? evt.options.location - : (process.env.GOOGLE_CLOUD_LOCATION ?? process.env.VERTEX_LOCATION ?? "global"), + project, + location, + // Continental multi-regions (eu, us) require Regional Endpoint Platform + // domains; the default {region}-aiplatform.googleapis.com does not resolve. + ...((location === "eu" || location === "us") && project && !evt.options.baseURL + ? { + baseURL: `https://aiplatform.${location}.rep.googleapis.com/v1/projects/${project}/locations/${location}/publishers/anthropic/models`, + } + : {}), }) }), "aisdk.language": Effect.fn(function* (evt) { diff --git a/packages/core/src/plugin/provider/kilo.ts b/packages/core/src/plugin/provider/kilo.ts index 47b8ec99cd..17436d9f96 100644 --- a/packages/core/src/plugin/provider/kilo.ts +++ b/packages/core/src/plugin/provider/kilo.ts @@ -1,15 +1,20 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const KiloPlugin = PluginV2.define({ id: PluginV2.ID.make("kilo"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("kilo")) return - evt.provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" - evt.provider.options.headers["X-Title"] = "opencode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai-compatible") continue + if (item.provider.endpoint.url !== "https://api.kilo.ai/api/gateway") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" + provider.options.headers["X-Title"] = "opencode" + }) + } }), } }), diff --git a/packages/core/src/plugin/provider/llmgateway.ts b/packages/core/src/plugin/provider/llmgateway.ts index da1ab282bd..de1872935c 100644 --- a/packages/core/src/plugin/provider/llmgateway.ts +++ b/packages/core/src/plugin/provider/llmgateway.ts @@ -1,17 +1,22 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const LLMGatewayPlugin = PluginV2.define({ id: PluginV2.ID.make("llmgateway"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("llmgateway")) return - if (evt.provider.enabled === false) return - evt.provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" - evt.provider.options.headers["X-Title"] = "opencode" - evt.provider.options.headers["X-Source"] = "opencode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.enabled === false) continue + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai-compatible") continue + if (item.provider.endpoint.url !== "https://api.llmgateway.io/v1") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" + provider.options.headers["X-Title"] = "opencode" + provider.options.headers["X-Source"] = "opencode" + }) + } }), } }), diff --git a/packages/core/src/plugin/provider/nvidia.ts b/packages/core/src/plugin/provider/nvidia.ts index 49ef6af0f6..0c1301c842 100644 --- a/packages/core/src/plugin/provider/nvidia.ts +++ b/packages/core/src/plugin/provider/nvidia.ts @@ -1,16 +1,21 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const NvidiaPlugin = PluginV2.define({ id: PluginV2.ID.make("nvidia"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("nvidia")) return - evt.provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" - evt.provider.options.headers["X-Title"] = "opencode" - evt.provider.options.headers["X-BILLING-INVOKE-ORIGIN"] ??= "OpenCode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai-compatible") continue + if (item.provider.endpoint.url !== "https://integrate.api.nvidia.com/v1") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" + provider.options.headers["X-Title"] = "opencode" + provider.options.headers["X-BILLING-INVOKE-ORIGIN"] ??= "OpenCode" + }) + } }), } }), diff --git a/packages/core/src/plugin/provider/openai.ts b/packages/core/src/plugin/provider/openai.ts index a81455f198..d76d7417f1 100644 --- a/packages/core/src/plugin/provider/openai.ts +++ b/packages/core/src/plugin/provider/openai.ts @@ -16,11 +16,17 @@ export const OpenAIPlugin = PluginV2.define({ if (evt.model.providerID !== ProviderV2.ID.openai) return evt.language = evt.sdk.responses(evt.model.apiID) }), - "model.update": Effect.fn(function* (evt) { - if (evt.model.providerID !== ProviderV2.ID.openai) return - // OpenAIPlugin sends OpenAI models through Responses; this alias is a - // chat-completions-only model, so remove it only from OpenAI's catalog. - if (evt.model.id === ModelV2.ID.make("gpt-5-chat-latest")) evt.cancel = true + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai") continue + if (!item.models.has(ModelV2.ID.make("gpt-5-chat-latest"))) continue + evt.model.update(item.provider.id, ModelV2.ID.make("gpt-5-chat-latest"), (model) => { + // OpenAIPlugin sends OpenAI models through Responses; this alias is a + // chat-completions-only model, so hide it only from OpenAI's catalog. + model.enabled = false + }) + } }), } }), diff --git a/packages/core/src/plugin/provider/opencode.ts b/packages/core/src/plugin/provider/opencode.ts index 10bbb62dad..411cbe091e 100644 --- a/packages/core/src/plugin/provider/opencode.ts +++ b/packages/core/src/plugin/provider/opencode.ts @@ -7,20 +7,25 @@ export const OpencodePlugin = PluginV2.define({ effect: Effect.gen(function* () { let hasKey = false return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.opencode) return + "catalog.transform": Effect.fn(function* (evt) { + const item = evt.data.find((record) => record.provider.id === ProviderV2.ID.opencode) + if (!item) return hasKey = Boolean( process.env.OPENCODE_API_KEY || - evt.provider.env.some((item) => process.env[item]) || - evt.provider.options.aisdk.provider.apiKey || - (evt.provider.enabled && evt.provider.enabled.via === "auth"), + item.provider.env.some((env) => process.env[env]) || + item.provider.options.aisdk.provider.apiKey || + (item.provider.enabled && item.provider.enabled.via === "account"), ) - if (!hasKey) evt.provider.options.aisdk.provider.apiKey = "public" - }), - "model.update": Effect.fn(function* (evt) { - if (evt.model.providerID !== ProviderV2.ID.opencode) return + evt.provider.update(item.provider.id, (provider) => { + if (!hasKey) provider.options.aisdk.provider.apiKey = "public" + }) if (hasKey) return - if (evt.model.cost.some((item) => item.input > 0)) evt.cancel = true + for (const model of item.models.values()) { + if (!model.cost.some((cost) => cost.input > 0)) continue + evt.model.update(item.provider.id, model.id, (draft) => { + draft.enabled = false + }) + } }), } }), diff --git a/packages/core/src/plugin/provider/openrouter.ts b/packages/core/src/plugin/provider/openrouter.ts index 976eea8c05..317f48158a 100644 --- a/packages/core/src/plugin/provider/openrouter.ts +++ b/packages/core/src/plugin/provider/openrouter.ts @@ -1,29 +1,34 @@ import { Effect } from "effect" import { ModelV2 } from "../../model" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const OpenRouterPlugin = PluginV2.define({ id: PluginV2.ID.make("openrouter"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.openrouter) return - evt.provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" - evt.provider.options.headers["X-Title"] = "opencode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@openrouter/ai-sdk-provider") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["HTTP-Referer"] = "https://opencode.ai/" + provider.options.headers["X-Title"] = "opencode" + }) + for (const modelID of [ModelV2.ID.make("gpt-5-chat-latest"), ModelV2.ID.make("openai/gpt-5-chat")]) { + if (!item.models.has(modelID)) continue + evt.model.update(item.provider.id, modelID, (model) => { + // These are OpenRouter-specific OpenAI chat aliases that do not work + // on the generic path. Keep custom providers with matching IDs untouched. + model.enabled = false + }) + } + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@openrouter/ai-sdk-provider") return const mod = yield* Effect.promise(() => import("@openrouter/ai-sdk-provider")) evt.sdk = mod.createOpenRouter(evt.options) }), - "model.update": Effect.fn(function* (evt) { - if (evt.model.providerID !== ProviderV2.ID.openrouter) return - // These are OpenRouter-specific OpenAI chat aliases that do not work on - // the generic path. Keep custom providers with matching IDs untouched. - if (evt.model.id === ModelV2.ID.make("gpt-5-chat-latest")) evt.cancel = true - if (evt.model.id === ModelV2.ID.make("openai/gpt-5-chat")) evt.cancel = true - }), } }), }) diff --git a/packages/core/src/plugin/provider/vercel.ts b/packages/core/src/plugin/provider/vercel.ts index 2108542b16..fa368d10d7 100644 --- a/packages/core/src/plugin/provider/vercel.ts +++ b/packages/core/src/plugin/provider/vercel.ts @@ -1,15 +1,19 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const VercelPlugin = PluginV2.define({ id: PluginV2.ID.make("vercel"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("vercel")) return - evt.provider.options.headers["http-referer"] = "https://opencode.ai/" - evt.provider.options.headers["x-title"] = "opencode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/vercel") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["http-referer"] = "https://opencode.ai/" + provider.options.headers["x-title"] = "opencode" + }) + } }), "aisdk.sdk": Effect.fn(function* (evt) { if (evt.package !== "@ai-sdk/vercel") return diff --git a/packages/core/src/plugin/provider/zenmux.ts b/packages/core/src/plugin/provider/zenmux.ts index 6bdd426010..3b0fcff165 100644 --- a/packages/core/src/plugin/provider/zenmux.ts +++ b/packages/core/src/plugin/provider/zenmux.ts @@ -1,15 +1,20 @@ import { Effect } from "effect" import { PluginV2 } from "../../plugin" -import { ProviderV2 } from "../../provider" export const ZenmuxPlugin = PluginV2.define({ id: PluginV2.ID.make("zenmux"), effect: Effect.gen(function* () { return { - "provider.update": Effect.fn(function* (evt) { - if (evt.provider.id !== ProviderV2.ID.make("zenmux")) return - evt.provider.options.headers["HTTP-Referer"] ??= "https://opencode.ai/" - evt.provider.options.headers["X-Title"] ??= "opencode" + "catalog.transform": Effect.fn(function* (evt) { + for (const item of evt.data) { + if (item.provider.endpoint.type !== "aisdk") continue + if (item.provider.endpoint.package !== "@ai-sdk/openai-compatible") continue + if (item.provider.endpoint.url !== "https://zenmux.ai/api/v1") continue + evt.provider.update(item.provider.id, (provider) => { + provider.options.headers["HTTP-Referer"] ??= "https://opencode.ai/" + provider.options.headers["X-Title"] ??= "opencode" + }) + } }), } }), diff --git a/packages/core/src/provider.ts b/packages/core/src/provider.ts index 7c1c966654..7ba2172ada 100644 --- a/packages/core/src/provider.ts +++ b/packages/core/src/provider.ts @@ -86,7 +86,7 @@ export class Info extends Schema.Class("ProviderV2.Info")({ name: Schema.String, }), Schema.Struct({ - via: Schema.Literal("auth"), + via: Schema.Literal("account"), service: Schema.String, }), Schema.Struct({ diff --git a/packages/core/src/util/error.ts b/packages/core/src/util/error.ts index 7338571f29..5fe41e1cff 100644 --- a/packages/core/src/util/error.ts +++ b/packages/core/src/util/error.ts @@ -65,5 +65,6 @@ export abstract class NamedError extends Error { public static readonly Unknown = NamedError.create("UnknownError", { message: Schema.String, + ref: Schema.optional(Schema.String), }) } diff --git a/packages/core/src/util/wildcard.ts b/packages/core/src/util/wildcard.ts new file mode 100644 index 0000000000..0a67817bcb --- /dev/null +++ b/packages/core/src/util/wildcard.ts @@ -0,0 +1,14 @@ +export * as Wildcard from "./wildcard" + +export function match(input: string, pattern: string) { + const normalized = input.replaceAll("\\", "/") + let escaped = pattern + .replaceAll("\\", "/") + .replace(/[.+^${}()|[\]\\]/g, "\\$&") + .replace(/\*/g, ".*") + .replace(/\?/g, ".") + + if (escaped.endsWith(" .*")) escaped = escaped.slice(0, -3) + "( .*)?" + + return new RegExp("^" + escaped + "$", process.platform === "win32" ? "si" : "s").test(normalized) +} diff --git a/packages/core/test/account.test.ts b/packages/core/test/account.test.ts new file mode 100644 index 0000000000..cf60740b1e --- /dev/null +++ b/packages/core/test/account.test.ts @@ -0,0 +1,284 @@ +import path from "path" +import { describe, expect } from "bun:test" +import { produce } from "immer" +import { Effect, Fiber, Layer, Option, Stream } from "effect" +import { AccountV2 } from "@opencode-ai/core/account" +import { Catalog } from "@opencode-ai/core/catalog" +import { EventV2 } from "@opencode-ai/core/event" +import { AppFileSystem } from "@opencode-ai/core/filesystem" +import { Global } from "@opencode-ai/core/global" +import { PluginV2 } from "@opencode-ai/core/plugin" +import { AccountPlugin } from "@opencode-ai/core/plugin/account" +import { ModelV2 } from "@opencode-ai/core/model" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { tmpdir } from "./fixture/tmpdir" +import { testEffect } from "./lib/effect" + +const it = testEffect(PluginV2.defaultLayer) + +function context( + records: { provider: ProviderV2.Info; models: Map }[], + updates: Array<{ id: ProviderV2.ID; enabled: ProviderV2.Info["enabled"]; apiKey?: string }>, +): Catalog.Context { + return { + data: records, + updateProvider: (providerID, fn) => context(records, updates).provider.update(providerID, fn), + updateModel: (providerID, modelID, fn) => context(records, updates).model.update(providerID, modelID, fn), + provider: { + update: (providerID, fn) => { + const record = records.find((item) => item.provider.id === providerID) + const provider = produce(record?.provider ?? ProviderV2.Info.empty(providerID), fn) + if (record) record.provider = provider + else records.push({ provider, models: new Map() }) + updates.push({ + id: providerID, + enabled: provider.enabled, + apiKey: + typeof provider.options.aisdk.provider.apiKey === "string" + ? provider.options.aisdk.provider.apiKey + : undefined, + }) + }, + remove: (providerID) => { + const index = records.findIndex((item) => item.provider.id === providerID) + if (index !== -1) records.splice(index, 1) + }, + }, + model: { + update: () => {}, + remove: () => {}, + }, + } +} + +function testLayer(dir: string) { + return AccountV2.layer.pipe( + Layer.provide(AppFileSystem.defaultLayer), + Layer.provideMerge(EventV2.defaultLayer), + Layer.provide( + Global.layerWith({ + data: dir, + cache: path.join(dir, "cache"), + config: path.join(dir, "config"), + state: path.join(dir, "state"), + tmp: path.join(dir, "tmp"), + bin: path.join(dir, "bin"), + log: path.join(dir, "log"), + repos: path.join(dir, "repos"), + }), + ), + ) +} + +describe("AccountV2", () => { + it.live("emits account lifecycle events", () => + Effect.acquireRelease( + Effect.promise(() => tmpdir()), + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), + ).pipe( + Effect.flatMap((tmp) => + Effect.gen(function* () { + const accounts = yield* AccountV2.Service + const eventSvc = yield* EventV2.Service + const addedFiber = yield* eventSvc + .subscribe(AccountV2.Event.Added) + .pipe(Stream.take(2), Stream.runCollect, Effect.forkScoped) + const switchedFiber = yield* eventSvc + .subscribe(AccountV2.Event.Switched) + .pipe(Stream.take(3), Stream.runCollect, Effect.forkScoped) + const removedFiber = yield* eventSvc + .subscribe(AccountV2.Event.Removed) + .pipe(Stream.take(1), Stream.runCollect, Effect.forkScoped) + + yield* Effect.yieldNow + + const first = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "raw-key" }), + }) + expect(first).toBeDefined() + if (!first) return + expect(first.description).toBe("default") + expect(first.credential.type).toBe("api") + if (first.credential.type === "api") expect(first.credential.key).toBe("raw-key") + + yield* accounts.update(first.id, { description: "keep" }) + const updated = yield* accounts.get(first.id) + expect(updated?.description).toBe("keep") + expect(updated?.credential.type).toBe("api") + if (updated?.credential.type === "api") expect(updated.credential.key).toBe("raw-key") + + const second = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "second-key" }), + }) + expect(second).toBeDefined() + if (!second) return + + yield* accounts.remove(second.id) + const added = Array.from(yield* Fiber.join(addedFiber)) + const switched = Array.from(yield* Fiber.join(switchedFiber)) + const removed = Array.from(yield* Fiber.join(removedFiber)) + expect(added.map((event) => event.data.account.id)).toEqual([first.id, second.id]) + expect(switched.map((event) => event.data)).toEqual([ + { serviceID: AccountV2.ServiceID.make("provider"), from: undefined, to: first.id }, + { serviceID: AccountV2.ServiceID.make("provider"), from: first.id, to: second.id }, + { serviceID: AccountV2.ServiceID.make("provider"), from: second.id, to: first.id }, + ]) + expect(removed[0]?.data.account.id).toBe(second.id) + }).pipe(Effect.provide(testLayer(tmp.path))), + ), + ), + ) + + it.live("always switches to newly created accounts", () => + Effect.acquireRelease( + Effect.promise(() => tmpdir()), + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), + ).pipe( + Effect.flatMap((tmp) => + Effect.gen(function* () { + const accounts = yield* AccountV2.Service + const eventSvc = yield* EventV2.Service + const switchedFiber = yield* eventSvc + .subscribe(AccountV2.Event.Switched) + .pipe(Stream.take(3), Stream.runCollect, Effect.forkScoped) + + yield* Effect.yieldNow + + const first = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "first-key" }), + }) + const second = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "second-key" }), + }) + const third = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "third-key" }), + }) + + expect(first).toBeDefined() + expect(second).toBeDefined() + expect(third).toBeDefined() + if (!first || !second || !third) return + + expect((yield* accounts.active(AccountV2.ServiceID.make("provider")))?.id).toBe(third.id) + expect(Array.from(yield* Fiber.join(switchedFiber)).map((event) => event.data)).toEqual([ + { serviceID: AccountV2.ServiceID.make("provider"), from: undefined, to: first.id }, + { serviceID: AccountV2.ServiceID.make("provider"), from: first.id, to: second.id }, + { serviceID: AccountV2.ServiceID.make("provider"), from: second.id, to: third.id }, + ]) + }).pipe(Effect.provide(testLayer(tmp.path))), + ), + ), + ) + + it.live("account plugin refreshes providers on account lifecycle events", () => + Effect.acquireRelease( + Effect.promise(() => tmpdir()), + (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()), + ).pipe( + Effect.flatMap((tmp) => + Effect.gen(function* () { + const accounts = yield* AccountV2.Service + const plugin = yield* PluginV2.Service + const records = [ + { + provider: ProviderV2.Info.empty(ProviderV2.ID.make("provider")), + models: new Map(), + }, + ] + const updates: Array<{ id: ProviderV2.ID; enabled: ProviderV2.Info["enabled"]; apiKey?: string }> = [] + const catalog = Catalog.Service.of({ + loader: () => Effect.die("unexpected catalog.loader"), + provider: { + get: () => Effect.die("unexpected provider.get"), + all: () => Effect.succeed([]), + available: () => Effect.succeed([]), + }, + model: { + get: () => Effect.die("unexpected model.get"), + all: () => Effect.succeed([]), + available: () => Effect.succeed([]), + default: () => Effect.succeed(Option.none()), + setDefault: () => Effect.die("unexpected model.setDefault"), + small: () => Effect.succeed(Option.none()), + }, + }) + + const eventSvc = yield* EventV2.Service + yield* plugin.add({ + ...AccountPlugin, + effect: AccountPlugin.effect.pipe( + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(EventV2.Service, eventSvc), + Effect.provideService(PluginV2.Service, plugin), + ), + }) + yield* Effect.yieldNow + + const first = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "first-key" }), + }) + expect(first).toBeDefined() + if (!first) return + yield* plugin.trigger("catalog.transform", context(records, updates), {}) + expect(updates).toEqual([ + { + id: ProviderV2.ID.make("provider"), + enabled: { via: "account", service: AccountV2.ServiceID.make("provider") }, + apiKey: "first-key", + }, + ]) + + updates.length = 0 + const second = yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("provider"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "second-key" }), + }) + expect(second).toBeDefined() + if (!second) return + yield* plugin.trigger("catalog.transform", context(records, updates), {}) + expect(updates).toEqual([ + { + id: ProviderV2.ID.make("provider"), + enabled: { via: "account", service: AccountV2.ServiceID.make("provider") }, + apiKey: "second-key", + }, + ]) + + updates.length = 0 + yield* accounts.activate(first.id) + yield* plugin.trigger("catalog.transform", context(records, updates), {}) + expect(updates).toEqual([ + { + id: ProviderV2.ID.make("provider"), + enabled: { via: "account", service: AccountV2.ServiceID.make("provider") }, + apiKey: "first-key", + }, + ]) + + updates.length = 0 + yield* accounts.remove(first.id) + yield* plugin.trigger("catalog.transform", context(records, updates), {}) + expect(updates).toEqual([ + { + id: ProviderV2.ID.make("provider"), + enabled: { via: "account", service: AccountV2.ServiceID.make("provider") }, + apiKey: "second-key", + }, + ]) + + updates.length = 0 + yield* accounts.remove(second.id) + yield* plugin.trigger("catalog.transform", context(records, updates), {}) + expect(updates).toEqual([]) + }).pipe(Effect.provide(testLayer(tmp.path))), + ), + ), + ) +}) diff --git a/packages/core/test/catalog.test.ts b/packages/core/test/catalog.test.ts index 594f42d1c8..97f816d005 100644 --- a/packages/core/test/catalog.test.ts +++ b/packages/core/test/catalog.test.ts @@ -1,5 +1,5 @@ import { describe, expect } from "bun:test" -import { DateTime, Effect, Fiber, Layer, Option, Stream } from "effect" +import { DateTime, Effect, Layer, Option } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { EventV2 } from "@opencode-ai/core/event" import { Location } from "@opencode-ai/core/location" @@ -22,24 +22,24 @@ describe("CatalogV2", () => { Effect.gen(function* () { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, (provider) => { - provider.endpoint = { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://default.example.com", - } - provider.options.aisdk.provider.baseURL = "https://override.example.com" - }) + yield* load((catalog) => + catalog.provider.update(providerID, (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://default.example.com", + } + provider.options.aisdk.provider.baseURL = "https://override.example.com" + }), + ) - const provider = yield* catalog.provider.get(providerID) - - expect(provider.endpoint).toEqual({ + expect((yield* catalog.provider.get(providerID)).endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://override.example.com", }) - expect(provider.options.aisdk.provider.baseURL).toBeUndefined() }), ) @@ -48,56 +48,27 @@ describe("CatalogV2", () => { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") const modelID = ModelV2.ID.make("model") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, (provider) => { - provider.endpoint = { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://provider.example.com", - } - }) - yield* catalog.model.update(providerID, modelID, (model) => { - model.endpoint = { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://model.example.com", - } - model.options.aisdk.provider.baseURL = "https://override.example.com" + yield* load((catalog) => { + catalog.provider.update(providerID, (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://provider.example.com", + } + }) + catalog.model.update(providerID, modelID, (model) => { + model.endpoint = { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://model.example.com" } + model.options.aisdk.provider.baseURL = "https://override.example.com" + }) }) - const model = yield* catalog.model.get(providerID, modelID) - - expect(model.endpoint).toEqual({ + expect((yield* catalog.model.get(providerID, modelID)).endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://override.example.com", }) - expect(model.options.aisdk.provider.baseURL).toBeUndefined() - }), - ) - - it.effect("publishes model updated events", () => - Effect.gen(function* () { - const catalog = yield* Catalog.Service - const events = yield* EventV2.Service - const providerID = ProviderV2.ID.make("test") - const modelID = ModelV2.ID.make("model") - const fiber = yield* events - .subscribe(Catalog.Event.ModelUpdated) - .pipe(Stream.take(1), Stream.runCollect, Effect.forkScoped) - - yield* Effect.yieldNow - yield* catalog.provider.update(providerID, () => {}) - yield* catalog.model.update(providerID, modelID, (model) => { - model.name = "Updated Model" - }) - const event = Array.from(yield* Fiber.join(fiber))[0] - - expect(event?.type).toBe("catalog.model.updated") - expect(event?.data.model.providerID).toBe(providerID) - expect(event?.data.model.id).toBe(modelID) - expect(event?.data.model.name).toBe("Updated Model") - expect(event?.location).toEqual({ directory: "test" }) }), ) @@ -106,19 +77,20 @@ describe("CatalogV2", () => { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") const modelID = ModelV2.ID.make("model") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, (provider) => { - provider.endpoint = { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://provider.example.com", - } + yield* load((catalog) => { + catalog.provider.update(providerID, (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://provider.example.com", + } + }) + catalog.model.update(providerID, modelID, () => {}) }) - yield* catalog.model.update(providerID, modelID, () => {}) - const model = yield* catalog.model.get(providerID, modelID) - - expect(model.endpoint).toEqual({ + expect((yield* catalog.model.get(providerID, modelID)).endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://provider.example.com", @@ -126,58 +98,91 @@ describe("CatalogV2", () => { }), ) - it.effect("runs provider hooks after baseURL is normalized", () => + it.effect("runs catalog transform hooks after baseURL is normalized", () => Effect.gen(function* () { const catalog = yield* Catalog.Service const plugin = yield* PluginV2.Service const providerID = ProviderV2.ID.make("test") const seen: unknown[] = [] + const load = yield* catalog.loader() yield* plugin.add({ id: PluginV2.ID.make("test"), effect: Effect.succeed({ - "provider.update": (evt) => + "catalog.transform": (evt) => Effect.sync(() => { - seen.push(evt.provider.endpoint.type) - if (evt.provider.endpoint.type === "aisdk") seen.push(evt.provider.endpoint.url) - seen.push(evt.provider.options.aisdk.provider.baseURL) + const item = evt.data.find((record) => record.provider.id === providerID) + if (!item) return + seen.push(item.provider.endpoint.type) + if (item?.provider.endpoint.type === "aisdk") seen.push(item.provider.endpoint.url) + seen.push(item?.provider.options.aisdk.provider.baseURL) }), }), }) - yield* catalog.provider.update(providerID, (provider) => { - provider.endpoint = { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - } - provider.options.aisdk.provider.baseURL = "https://provider.example.com" - }) + yield* load((catalog) => + catalog.provider.update(providerID, (provider) => { + provider.endpoint = { type: "aisdk", package: "@ai-sdk/openai-compatible" } + provider.options.aisdk.provider.baseURL = "https://provider.example.com" + }), + ) expect(seen).toEqual(["aisdk", "https://provider.example.com", undefined]) }), ) + it.effect("runs catalog transform when a plugin is added", () => + Effect.gen(function* () { + const catalog = yield* Catalog.Service + const plugin = yield* PluginV2.Service + const providerID = ProviderV2.ID.make("test") + const load = yield* catalog.loader() + + yield* load((catalog) => + catalog.provider.update(providerID, (provider) => { + provider.name = "Before" + }), + ) + yield* plugin.add({ + id: PluginV2.ID.make("test-transform"), + effect: Effect.succeed({ + "catalog.transform": (evt) => + Effect.sync(() => + evt.provider.update(providerID, (provider) => { + provider.name = "After" + }), + ), + }), + }) + yield* Effect.yieldNow + + expect((yield* catalog.provider.get(providerID)).name).toBe("After") + }), + ) + it.effect("resolves provider and model option merges", () => Effect.gen(function* () { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") const modelID = ModelV2.ID.make("model") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, (provider) => { - provider.options.headers.provider = "provider" - provider.options.headers.shared = "provider" - provider.options.body.provider = true - provider.options.aisdk.provider.provider = true - }) - yield* catalog.model.update(providerID, modelID, (model) => { - model.options.headers.model = "model" - model.options.headers.shared = "model" - model.options.body.model = true - model.options.aisdk.provider.model = true - model.options.aisdk.request.request = true + yield* load((catalog) => { + catalog.provider.update(providerID, (provider) => { + provider.options.headers.provider = "provider" + provider.options.headers.shared = "provider" + provider.options.body.provider = true + provider.options.aisdk.provider.provider = true + }) + catalog.model.update(providerID, modelID, (model) => { + model.options.headers.model = "model" + model.options.headers.shared = "model" + model.options.body.model = true + model.options.aisdk.provider.model = true + model.options.aisdk.request.request = true + }) }) const model = yield* catalog.model.get(providerID, modelID) - expect(model.options.headers).toEqual({ provider: "provider", shared: "model", model: "model" }) expect(model.options.body).toEqual({ provider: true, model: true }) expect(model.options.aisdk.provider).toEqual({ provider: true, model: true }) @@ -189,20 +194,21 @@ describe("CatalogV2", () => { Effect.gen(function* () { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, (provider) => { - provider.enabled = { via: "custom", data: {} } - }) - yield* catalog.model.update(providerID, ModelV2.ID.make("old"), (model) => { - model.time.released = DateTime.makeUnsafe(1000) - }) - yield* catalog.model.update(providerID, ModelV2.ID.make("new"), (model) => { - model.time.released = DateTime.makeUnsafe(2000) + yield* load((catalog) => { + catalog.provider.update(providerID, (provider) => { + provider.enabled = { via: "custom", data: {} } + }) + catalog.model.update(providerID, ModelV2.ID.make("old"), (model) => { + model.time.released = DateTime.makeUnsafe(1000) + }) + catalog.model.update(providerID, ModelV2.ID.make("new"), (model) => { + model.time.released = DateTime.makeUnsafe(2000) + }) }) - const model = yield* catalog.model.default() - - expect(Option.getOrUndefined(model)?.id).toMatch("new") + expect(Option.getOrUndefined(yield* catalog.model.default())?.id).toMatch("new") }), ) @@ -210,24 +216,25 @@ describe("CatalogV2", () => { Effect.gen(function* () { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.make("test") + const load = yield* catalog.loader() - yield* catalog.provider.update(providerID, () => {}) - yield* catalog.model.update(providerID, ModelV2.ID.make("cheap-large"), (model) => { - model.capabilities.input = ["text"] - model.capabilities.output = ["text"] - model.cost = [{ input: 1, output: 1, cache: { read: 0, write: 0 } }] - model.time.released = DateTime.makeUnsafe(Date.now()) - }) - yield* catalog.model.update(providerID, ModelV2.ID.make("expensive-mini"), (model) => { - model.capabilities.input = ["text"] - model.capabilities.output = ["text"] - model.cost = [{ input: 10, output: 10, cache: { read: 0, write: 0 } }] - model.time.released = DateTime.makeUnsafe(Date.now()) + yield* load((catalog) => { + catalog.provider.update(providerID, () => {}) + catalog.model.update(providerID, ModelV2.ID.make("cheap-large"), (model) => { + model.capabilities.input = ["text"] + model.capabilities.output = ["text"] + model.cost = [{ input: 1, output: 1, cache: { read: 0, write: 0 } }] + model.time.released = DateTime.makeUnsafe(Date.now()) + }) + catalog.model.update(providerID, ModelV2.ID.make("expensive-mini"), (model) => { + model.capabilities.input = ["text"] + model.capabilities.output = ["text"] + model.cost = [{ input: 10, output: 10, cache: { read: 0, write: 0 } }] + model.time.released = DateTime.makeUnsafe(Date.now()) + }) }) - const model = yield* catalog.model.small(providerID) - - expect(Option.getOrUndefined(model)?.id).toMatch("expensive-mini") + expect(Option.getOrUndefined(yield* catalog.model.small(providerID))?.id).toMatch("expensive-mini") }), ) }) diff --git a/packages/core/test/effect/cross-spawn-spawner.test.ts b/packages/core/test/effect/cross-spawn-spawner.test.ts index 627db8ef36..a3f74f671d 100644 --- a/packages/core/test/effect/cross-spawn-spawner.test.ts +++ b/packages/core/test/effect/cross-spawn-spawner.test.ts @@ -111,7 +111,7 @@ describe("cross-spawn spawner", () => { ChildProcess.make(process.execPath, ["-e", "process.stdout.write(process.cwd())"], { cwd: tmp.path }), ), ) - expect(out).toBe(tmp.path) + expect(yield* Effect.promise(() => fs.realpath(out))).toBe(yield* Effect.promise(() => fs.realpath(tmp.path))) }), ) @@ -119,7 +119,9 @@ describe("cross-spawn spawner", () => { "fails for invalid cwd", Effect.gen(function* () { const exit = yield* Effect.exit( - ChildProcess.make("echo", ["test"], { cwd: "/nonexistent/directory/path" }).asEffect(), + ChildProcessSpawner.ChildProcessSpawner.use((svc) => + svc.spawn(ChildProcess.make("echo", ["test"], { cwd: "/nonexistent/directory/path" })), + ), ) expect(Exit.isFailure(exit)).toBe(true) }), diff --git a/packages/core/test/models.test.ts b/packages/core/test/models.test.ts index e13d711202..a3a10cd01e 100644 --- a/packages/core/test/models.test.ts +++ b/packages/core/test/models.test.ts @@ -4,7 +4,8 @@ import { HttpClient, HttpClientResponse } from "effect/unstable/http" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Flag } from "@opencode-ai/core/flag/flag" import { Global } from "@opencode-ai/core/global" -import { ModelsDev } from "@opencode-ai/core/models" +import { ModelsDev } from "@opencode-ai/core/models-dev" +import { EventV2 } from "@opencode-ai/core/event" import { it } from "./lib/effect" import { rm, writeFile, utimes, mkdir } from "fs/promises" import path from "path" @@ -92,6 +93,7 @@ const buildLayer = (state: Ref.Ref) => Layer.fresh(ModelsDev.layer).pipe( Layer.provide(Layer.succeed(HttpClient.HttpClient, makeMockClient(state))), Layer.provide(AppFileSystem.defaultLayer), + Layer.provide(EventV2.defaultLayer), ) const writeCache = (data: object, mtimeMs?: number) => @@ -136,14 +138,14 @@ describe("ModelsDev Service", () => { }), ) - it.live("get() returns bundled snapshot when disk empty and fetch disabled", () => + it.live("get() returns empty catalog when disk empty, fetch disabled, and no bundled snapshot is injected", () => Effect.gen(function* () { const state = yield* Ref.make(initialState) const result = yield* provided( state, ModelsDev.Service.use((s) => s.get()), ) - expect(Object.keys(result).length).toBeGreaterThan(0) + expect(result).toEqual({}) const final = yield* Ref.get(state) expect(final.calls).toEqual([]) }), diff --git a/packages/core/test/plugin/provider-amazon-bedrock.test.ts b/packages/core/test/plugin/provider-amazon-bedrock.test.ts index c70ada08d9..f2034eb1e3 100644 --- a/packages/core/test/plugin/provider-amazon-bedrock.test.ts +++ b/packages/core/test/plugin/provider-amazon-bedrock.test.ts @@ -1,7 +1,9 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { AmazonBedrockPlugin } from "@opencode-ai/core/plugin/provider/amazon-bedrock" +import { ProviderV2 } from "@opencode-ai/core/provider" import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" function bedrockBaseURL(sdk: unknown, modelID = "anthropic.claude-sonnet-4-5") { @@ -20,27 +22,30 @@ describe("AmazonBedrockPlugin", () => { it.effect("moves endpoint option to endpoint URL", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AmazonBedrockPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("amazon-bedrock", { - options: { - headers: {}, - body: {}, - aisdk: { provider: { endpoint: "https://bedrock.example" }, request: {} }, - }, - }), - cancel: false, - }, - ) - expect(result.provider.endpoint).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const bedrock = provider("amazon-bedrock", { + endpoint: { type: "aisdk", package: "@ai-sdk/amazon-bedrock" }, + options: { + headers: {}, + body: {}, + aisdk: { provider: { endpoint: "https://bedrock.example" }, request: {} }, + }, + }) + catalog.provider.update(bedrock.id, (item) => { + item.endpoint = bedrock.endpoint + item.options = bedrock.options + }) + }) + const result = yield* catalog.provider.get(ProviderV2.ID.amazonBedrock) + expect(result.endpoint).toEqual({ type: "aisdk", - package: "test-provider", + package: "@ai-sdk/amazon-bedrock", url: "https://bedrock.example", }) - expect(result.provider.options.aisdk.provider.endpoint).toBeUndefined() + expect(result.options.aisdk.provider.endpoint).toBeUndefined() }), ) diff --git a/packages/core/test/plugin/provider-anthropic.test.ts b/packages/core/test/plugin/provider-anthropic.test.ts index bbea4a3721..0a1d5662d3 100644 --- a/packages/core/test/plugin/provider-anthropic.test.ts +++ b/packages/core/test/plugin/provider-anthropic.test.ts @@ -1,37 +1,43 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { AnthropicPlugin } from "@opencode-ai/core/plugin/provider/anthropic" +import { ProviderV2 } from "@opencode-ai/core/provider" import { it, model, provider } from "./provider-helper" describe("AnthropicPlugin", () => { it.effect("applies legacy beta headers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AnthropicPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("anthropic", { - options: { headers: { Existing: "1" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - expect(result.provider.options.headers["anthropic-beta"]).toBe( + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("anthropic", { + endpoint: { type: "aisdk", package: "@ai-sdk/anthropic" }, + options: { headers: { Existing: "1" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.anthropic)).options.headers["anthropic-beta"]).toBe( "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14", ) - expect(result.provider.options.headers.Existing).toBe("1") + expect((yield* catalog.provider.get(ProviderV2.ID.anthropic)).options.headers.Existing).toBe("1") }), ) it.effect("ignores non-Anthropic providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AnthropicPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("openai"), cancel: false }) - expect(result.provider.options.headers["anthropic-beta"]).toBeUndefined() + const load = yield* catalog.loader() + yield* load((catalog) => catalog.provider.update(provider("openai").id, () => {})) + expect((yield* catalog.provider.get(ProviderV2.ID.openai)).options.headers["anthropic-beta"]).toBeUndefined() }), ) diff --git a/packages/core/test/plugin/provider-azure-cognitive-services.test.ts b/packages/core/test/plugin/provider-azure-cognitive-services.test.ts index b835cbeeff..8b8baacb7e 100644 --- a/packages/core/test/plugin/provider-azure-cognitive-services.test.ts +++ b/packages/core/test/plugin/provider-azure-cognitive-services.test.ts @@ -1,7 +1,9 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { AzureCognitiveServicesPlugin } from "@opencode-ai/core/plugin/provider/azure" +import { ProviderV2 } from "@opencode-ai/core/provider" import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" describe("AzureCognitiveServicesPlugin", () => { @@ -9,20 +11,22 @@ describe("AzureCognitiveServicesPlugin", () => { withEnv({ AZURE_COGNITIVE_SERVICES_RESOURCE_NAME: "cognitive" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzureCognitiveServicesPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("azure-cognitive-services"), cancel: false }, - ) - expect(result.provider.endpoint).toEqual({ - type: "aisdk", - package: "test-provider", + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.make("azure-cognitive-services"), (item) => { + item.endpoint = { type: "aisdk", package: "@ai-sdk/openai-compatible" } + }) }) - expect(result.provider.options.aisdk.provider.baseURL).toBe( - "https://cognitive.cognitiveservices.azure.com/openai", - ) - expect(result.provider.options.aisdk.provider.resourceName).toBeUndefined() + const result = yield* catalog.provider.get(ProviderV2.ID.make("azure-cognitive-services")) + expect(result.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://cognitive.cognitiveservices.azure.com/openai", + }) + expect(result.options.aisdk.provider.baseURL).toBeUndefined() + expect(result.options.aisdk.provider.resourceName).toBeUndefined() }), ), ) @@ -31,17 +35,27 @@ describe("AzureCognitiveServicesPlugin", () => { withEnv({ AZURE_COGNITIVE_SERVICES_RESOURCE_NAME: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzureCognitiveServicesPlugin) - const azure = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("azure-cognitive-services"), cancel: false }, - ) - const other = yield* plugin.trigger("provider.update", {}, { provider: provider("openai"), cancel: false }) - expect(azure.provider.options.aisdk.provider.baseURL).toBeUndefined() - expect(azure.provider.endpoint).toEqual({ type: "aisdk", package: "test-provider" }) - expect(other.provider.options.aisdk.provider.baseURL).toBeUndefined() - expect(other.provider.endpoint).toEqual({ type: "aisdk", package: "test-provider" }) + const load = yield* catalog.loader() + yield* load((catalog) => { + const azure = provider("azure-cognitive-services", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible" }, + }) + const openai = provider("openai") + catalog.provider.update(azure.id, (item) => { + item.endpoint = azure.endpoint + }) + catalog.provider.update(openai.id, (item) => { + item.endpoint = openai.endpoint + }) + }) + const azure = yield* catalog.provider.get(ProviderV2.ID.make("azure-cognitive-services")) + const openai = yield* catalog.provider.get(ProviderV2.ID.openai) + expect(azure.options.aisdk.provider.baseURL).toBeUndefined() + expect(azure.endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible" }) + expect(openai.options.aisdk.provider.baseURL).toBeUndefined() + expect(openai.endpoint).toEqual({ type: "aisdk", package: "test-provider" }) }), ), ) diff --git a/packages/core/test/plugin/provider-azure.test.ts b/packages/core/test/plugin/provider-azure.test.ts index 5121b1eec0..8c8995a372 100644 --- a/packages/core/test/plugin/provider-azure.test.ts +++ b/packages/core/test/plugin/provider-azure.test.ts @@ -1,22 +1,40 @@ import { describe, expect } from "bun:test" import { Effect, Layer } from "effect" -import { AuthV2 } from "@opencode-ai/core/auth" +import { AccountV2 } from "@opencode-ai/core/account" +import { Catalog } from "@opencode-ai/core/catalog" +import { EventV2 } from "@opencode-ai/core/event" +import { Location } from "@opencode-ai/core/location" import { PluginV2 } from "@opencode-ai/core/plugin" -import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { AccountPlugin } from "@opencode-ai/core/plugin/account" import { AzurePlugin } from "@opencode-ai/core/plugin/provider/azure" +import { ProviderV2 } from "@opencode-ai/core/provider" import { testEffect } from "../lib/effect" import { fakeSelectorSdk, it, model, npmLayer, provider, withEnv } from "./provider-helper" -const itWithAuth = testEffect(Layer.mergeAll(PluginV2.defaultLayer, AuthV2.defaultLayer, npmLayer)) +const itWithAccount = testEffect( + Catalog.layer.pipe( + Layer.provideMerge(PluginV2.defaultLayer), + Layer.provideMerge(AccountV2.defaultLayer), + Layer.provideMerge(EventV2.defaultLayer), + Layer.provideMerge(Layer.succeed(Location.Service, Location.Service.of({ directory: "test" }))), + Layer.provideMerge(npmLayer), + ), +) describe("AzurePlugin", () => { it.effect("resolves resourceName from env", () => withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzurePlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("azure"), cancel: false }) - expect(result.provider.options.aisdk.provider.resourceName).toBe("from-env") + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.azure, (item) => { + item.endpoint = { type: "aisdk", package: "@ai-sdk/azure" } + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.azure)).options.aisdk.provider.resourceName).toBe("from-env") }), ), ) @@ -25,25 +43,29 @@ describe("AzurePlugin", () => { withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzurePlugin) - const azure = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("azure", { - options: { headers: {}, body: {}, aisdk: { provider: { resourceName: "from-config" }, request: {} } }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => { + const azure = provider("azure", { + endpoint: { type: "aisdk", package: "@ai-sdk/azure" }, + options: { headers: {}, body: {}, aisdk: { provider: { resourceName: "from-config" }, request: {} } }, + }) + catalog.provider.update(azure.id, (item) => { + item.endpoint = azure.endpoint + item.options = azure.options + }) + catalog.provider.update(ProviderV2.ID.openai, () => {}) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.azure)).options.aisdk.provider.resourceName).toBe( + "from-config", ) - const other = yield* plugin.trigger("provider.update", {}, { provider: provider("openai"), cancel: false }) - expect(azure.provider.options.aisdk.provider.resourceName).toBe("from-config") - expect(other.provider.options.aisdk.provider.resourceName).toBeUndefined() + expect((yield* catalog.provider.get(ProviderV2.ID.openai)).options.aisdk.provider.resourceName).toBeUndefined() }), ), ) - itWithAuth.effect("prefers auth resourceName over env", () => + itWithAccount.effect("prefers account resourceName over env", () => withEnv( { AZURE_RESOURCE_NAME: "from-env", @@ -51,23 +73,36 @@ describe("AzurePlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service - const auth = yield* AuthV2.Service - yield* auth.create({ - serviceID: AuthV2.ServiceID.make("azure"), - credential: new AuthV2.ApiKeyCredential({ + const accounts = yield* AccountV2.Service + const catalog = yield* Catalog.Service + const events = yield* EventV2.Service + yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("azure"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "key", - metadata: { resourceName: "from-auth" }, + metadata: { resourceName: "from-account" }, }), - active: true, }) yield* plugin.add({ - ...AuthPlugin, - effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + ...AccountPlugin, + effect: AccountPlugin.effect.pipe( + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(EventV2.Service, events), + Effect.provideService(PluginV2.Service, plugin), + ), }) yield* plugin.add(AzurePlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("azure"), cancel: false }) - expect(result.provider.options.aisdk.provider.resourceName).toBe("from-auth") + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.azure, (item) => { + item.endpoint = { type: "aisdk", package: "@ai-sdk/azure" } + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.azure)).options.aisdk.provider.resourceName).toBe( + "from-account", + ) }), ), ) @@ -76,18 +111,20 @@ describe("AzurePlugin", () => { withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzurePlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("azure", { - options: { headers: {}, body: {}, aisdk: { provider: { resourceName: "" }, request: {} } }, - }), - cancel: false, - }, - ) - expect(result.provider.options.aisdk.provider.resourceName).toBe("from-env") + const load = yield* catalog.loader() + yield* load((catalog) => { + const azure = provider("azure", { + endpoint: { type: "aisdk", package: "@ai-sdk/azure" }, + options: { headers: {}, body: {}, aisdk: { provider: { resourceName: "" }, request: {} } }, + }) + catalog.provider.update(azure.id, (item) => { + item.endpoint = azure.endpoint + item.options = azure.options + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.azure)).options.aisdk.provider.resourceName).toBe("from-env") }), ), ) @@ -96,18 +133,20 @@ describe("AzurePlugin", () => { withEnv({ AZURE_RESOURCE_NAME: "from-env" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(AzurePlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("azure", { - options: { headers: {}, body: {}, aisdk: { provider: { resourceName: " " }, request: {} } }, - }), - cancel: false, - }, - ) - expect(result.provider.options.aisdk.provider.resourceName).toBe("from-env") + const load = yield* catalog.loader() + yield* load((catalog) => { + const azure = provider("azure", { + endpoint: { type: "aisdk", package: "@ai-sdk/azure" }, + options: { headers: {}, body: {}, aisdk: { provider: { resourceName: " " }, request: {} } }, + }) + catalog.provider.update(azure.id, (item) => { + item.endpoint = azure.endpoint + item.options = azure.options + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.azure)).options.aisdk.provider.resourceName).toBe("from-env") }), ), ) diff --git a/packages/core/test/plugin/provider-cerebras.test.ts b/packages/core/test/plugin/provider-cerebras.test.ts index 7270d5367a..dd8d34c7df 100644 --- a/packages/core/test/plugin/provider-cerebras.test.ts +++ b/packages/core/test/plugin/provider-cerebras.test.ts @@ -1,8 +1,10 @@ import { describe, expect, mock } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { CerebrasPlugin } from "@opencode-ai/core/plugin/provider/cerebras" -import { it, model, provider } from "./provider-helper" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { it, model } from "./provider-helper" const cerebrasOptions: Record[] = [] @@ -20,27 +22,30 @@ describe("CerebrasPlugin", () => { it.effect("applies the legacy integration header", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(CerebrasPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("cerebras", { - options: { headers: { Existing: "1" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - expect(result.provider.options.headers).toEqual({ Existing: "1", "X-Cerebras-3rd-Party-Integration": "opencode" }) + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.make("cerebras"), (item) => { + item.endpoint = { type: "aisdk", package: "@ai-sdk/cerebras" } + item.options.headers.Existing = "1" + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("cerebras"))).options.headers).toEqual({ + Existing: "1", + "X-Cerebras-3rd-Party-Integration": "opencode", + }) }), ) it.effect("ignores non-Cerebras providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(CerebrasPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("groq"), cancel: false }) - expect(result.provider.options.headers).toEqual({}) + const load = yield* catalog.loader() + yield* load((catalog) => catalog.provider.update(ProviderV2.ID.make("groq"), () => {})) + expect((yield* catalog.provider.get(ProviderV2.ID.make("groq"))).options.headers).toEqual({}) }), ) diff --git a/packages/core/test/plugin/provider-cloudflare-workers-ai.test.ts b/packages/core/test/plugin/provider-cloudflare-workers-ai.test.ts index 10aba171c3..d1db7b27a1 100644 --- a/packages/core/test/plugin/provider-cloudflare-workers-ai.test.ts +++ b/packages/core/test/plugin/provider-cloudflare-workers-ai.test.ts @@ -1,14 +1,26 @@ import { describe, expect } from "bun:test" import { Effect, Layer } from "effect" -import { AuthV2 } from "@opencode-ai/core/auth" +import { AccountV2 } from "@opencode-ai/core/account" +import { Catalog } from "@opencode-ai/core/catalog" +import { Location } from "@opencode-ai/core/location" +import { EventV2 } from "@opencode-ai/core/event" import { ModelV2 } from "@opencode-ai/core/model" import { PluginV2 } from "@opencode-ai/core/plugin" -import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { AccountPlugin } from "@opencode-ai/core/plugin/account" import { CloudflareWorkersAIPlugin } from "@opencode-ai/core/plugin/provider/cloudflare-workers-ai" +import { ProviderV2 } from "@opencode-ai/core/provider" import { testEffect } from "../lib/effect" -import { fakeSelectorSdk, it, model, npmLayer, provider, withEnv } from "./provider-helper" +import { fakeSelectorSdk, it, model, npmLayer, withEnv } from "./provider-helper" -const itWithAuth = testEffect(Layer.mergeAll(PluginV2.defaultLayer, AuthV2.defaultLayer, npmLayer)) +const itWithAccount = testEffect( + Catalog.layer.pipe( + Layer.provideMerge(PluginV2.defaultLayer), + Layer.provideMerge(AccountV2.defaultLayer), + Layer.provideMerge(EventV2.defaultLayer), + Layer.provideMerge(Layer.succeed(Location.Service, Location.Service.of({ directory: "test" }))), + Layer.provideMerge(npmLayer), + ), +) function cloudflareLanguage(sdk: unknown, modelID = "@cf/model") { return (sdk as { languageModel: (id: string) => { config: CloudflareConfig; provider: string } }).languageModel( @@ -34,22 +46,25 @@ describe("CloudflareWorkersAIPlugin", () => { withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct", CLOUDFLARE_API_KEY: "key" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(CloudflareWorkersAIPlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("cloudflare-workers-ai"), cancel: false }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => { + provider.endpoint = { type: "aisdk", package: "test-provider" } + }), ) + const provider = yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai")) const sdk = yield* plugin.trigger( "aisdk.sdk", { - model: model("cloudflare-workers-ai", "@cf/model", { endpoint: updated.provider.endpoint }), + model: model("cloudflare-workers-ai", "@cf/model", { endpoint: provider.endpoint }), package: "@ai-sdk/openai-compatible", options: { name: "cloudflare-workers-ai", headers: { custom: "header" } }, }, {}, ) - expect(updated.provider.endpoint).toEqual({ + expect(provider.endpoint).toEqual({ type: "aisdk", package: "test-provider", url: "https://api.cloudflare.com/client/v4/accounts/acct/ai/v1", @@ -63,18 +78,15 @@ describe("CloudflareWorkersAIPlugin", () => { withEnv({ CLOUDFLARE_ACCOUNT_ID: "acct" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(CloudflareWorkersAIPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("cloudflare-workers-ai", { - endpoint: { type: "aisdk", package: "test-provider", url: "https://proxy.example/v1" }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => { + provider.endpoint = { type: "aisdk", package: "test-provider", url: "https://proxy.example/v1" } + }), ) - expect(result.provider.endpoint).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai"))).endpoint).toEqual({ type: "aisdk", package: "test-provider", url: "https://proxy.example/v1", @@ -104,7 +116,7 @@ describe("CloudflareWorkersAIPlugin", () => { ), ) - itWithAuth.effect("falls back to auth account metadata when account env is absent", () => + itWithAccount.effect("falls back to account metadata when account env is absent", () => withEnv( { CLOUDFLARE_ACCOUNT_ID: undefined, @@ -113,30 +125,37 @@ describe("CloudflareWorkersAIPlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service - const auth = yield* AuthV2.Service - yield* auth.create({ - serviceID: AuthV2.ServiceID.make("cloudflare-workers-ai"), - credential: new AuthV2.ApiKeyCredential({ + const accounts = yield* AccountV2.Service + const catalog = yield* Catalog.Service + const events = yield* EventV2.Service + yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("cloudflare-workers-ai"), + credential: new AccountV2.ApiKeyCredential({ type: "api", - key: "auth-key", - metadata: { accountId: "auth-acct" }, + key: "account-key", + metadata: { accountId: "account-acct" }, }), - active: true, }) yield* plugin.add({ - ...AuthPlugin, - effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + ...AccountPlugin, + effect: AccountPlugin.effect.pipe( + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(EventV2.Service, events), + Effect.provideService(PluginV2.Service, plugin), + ), }) yield* plugin.add(CloudflareWorkersAIPlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("cloudflare-workers-ai"), cancel: false }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => { + provider.endpoint = { type: "aisdk", package: "test-provider" } + }), ) - expect(updated.provider.endpoint).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai"))).endpoint).toEqual({ type: "aisdk", package: "test-provider", - url: "https://api.cloudflare.com/client/v4/accounts/auth-acct/ai/v1", + url: "https://api.cloudflare.com/client/v4/accounts/account-acct/ai/v1", }) }), ), @@ -146,18 +165,16 @@ describe("CloudflareWorkersAIPlugin", () => { withEnv({ CLOUDFLARE_ACCOUNT_ID: "env-acct" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(CloudflareWorkersAIPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("cloudflare-workers-ai", { - options: { headers: {}, body: {}, aisdk: { provider: { accountId: "configured-acct" }, request: {} } }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("cloudflare-workers-ai"), (provider) => { + provider.endpoint = { type: "aisdk", package: "test-provider" } + provider.options.aisdk.provider.accountId = "configured-acct" + }), ) - expect(result.provider.endpoint).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("cloudflare-workers-ai"))).endpoint).toEqual({ type: "aisdk", package: "test-provider", url: "https://api.cloudflare.com/client/v4/accounts/env-acct/ai/v1", diff --git a/packages/core/test/plugin/provider-github-copilot.test.ts b/packages/core/test/plugin/provider-github-copilot.test.ts index e2bd899ff3..51822c26ac 100644 --- a/packages/core/test/plugin/provider-github-copilot.test.ts +++ b/packages/core/test/plugin/provider-github-copilot.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { ModelV2 } from "@opencode-ai/core/model" import { PluginV2 } from "@opencode-ai/core/plugin" import { GithubCopilotPlugin } from "@opencode-ai/core/plugin/provider/github-copilot" +import { ProviderV2 } from "@opencode-ai/core/provider" import { fakeSelectorSdk, it, model } from "./provider-helper" describe("GithubCopilotPlugin", () => { @@ -145,29 +147,35 @@ describe("GithubCopilotPlugin", () => { }), ) - it.effect("filters gpt-5-chat-latest before Copilot language selection", () => + it.effect("disables gpt-5-chat-latest before Copilot language selection", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GithubCopilotPlugin) - const result = yield* plugin.trigger( - "model.update", - {}, - { model: model("github-copilot", "gpt-5-chat-latest"), cancel: false }, - ) - expect(result.cancel).toBe(true) + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.make("github-copilot"), () => {}) + catalog.model.update(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-chat-latest"), () => {}) + }) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("github-copilot"), ModelV2.ID.make("gpt-5-chat-latest"))).enabled, + ).toBe(false) }), ) - it.effect("does not filter gpt-5-chat-latest for non-Copilot providers", () => + it.effect("does not disable gpt-5-chat-latest for non-Copilot providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GithubCopilotPlugin) - const result = yield* plugin.trigger( - "model.update", - {}, - { model: model("custom-copilot", "gpt-5-chat-latest"), cancel: false }, - ) - expect(result.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.make("custom-copilot"), () => {}) + catalog.model.update(ProviderV2.ID.make("custom-copilot"), ModelV2.ID.make("gpt-5-chat-latest"), () => {}) + }) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("custom-copilot"), ModelV2.ID.make("gpt-5-chat-latest"))).enabled, + ).toBe(true) }), ) diff --git a/packages/core/test/plugin/provider-gitlab.test.ts b/packages/core/test/plugin/provider-gitlab.test.ts index 56a22649a9..e785fbbb7f 100644 --- a/packages/core/test/plugin/provider-gitlab.test.ts +++ b/packages/core/test/plugin/provider-gitlab.test.ts @@ -1,11 +1,15 @@ import { describe, expect, mock } from "bun:test" import { Effect, Layer } from "effect" -import { AuthV2 } from "@opencode-ai/core/auth" +import { AccountV2 } from "@opencode-ai/core/account" +import { Catalog } from "@opencode-ai/core/catalog" +import { EventV2 } from "@opencode-ai/core/event" +import { Location } from "@opencode-ai/core/location" import { PluginV2 } from "@opencode-ai/core/plugin" -import { AuthPlugin } from "@opencode-ai/core/plugin/auth" +import { AccountPlugin } from "@opencode-ai/core/plugin/account" import { GitLabPlugin } from "@opencode-ai/core/plugin/provider/gitlab" +import { ProviderV2 } from "@opencode-ai/core/provider" import { testEffect } from "../lib/effect" -import { it, model, npmLayer, provider, withEnv } from "./provider-helper" +import { it, model, npmLayer, withEnv } from "./provider-helper" const gitlabSDKOptions: Record[] = [] @@ -22,7 +26,15 @@ void mock.module("gitlab-ai-provider", () => ({ isWorkflowModel: (id: string) => id === "duo-workflow" || id === "duo-workflow-exact", })) -const itWithAuth = testEffect(Layer.mergeAll(PluginV2.defaultLayer, AuthV2.defaultLayer, npmLayer)) +const itWithAccount = testEffect( + Catalog.layer.pipe( + Layer.provideMerge(PluginV2.defaultLayer), + Layer.provideMerge(AccountV2.defaultLayer), + Layer.provideMerge(EventV2.defaultLayer), + Layer.provideMerge(Layer.succeed(Location.Service, Location.Service.of({ directory: "test" }))), + Layer.provideMerge(npmLayer), + ), +) describe("GitLabPlugin", () => { it.effect("creates SDKs with legacy default instance URL, token env, headers, and feature flags", () => @@ -141,7 +153,7 @@ describe("GitLabPlugin", () => { }), ) - itWithAuth.effect("uses active API auth token over GITLAB_TOKEN", () => + itWithAccount.effect("uses active account API token over GITLAB_TOKEN", () => withEnv( { GITLAB_TOKEN: "env-token", @@ -150,33 +162,41 @@ describe("GitLabPlugin", () => { Effect.gen(function* () { gitlabSDKOptions.length = 0 const plugin = yield* PluginV2.Service - const auth = yield* AuthV2.Service - yield* auth.create({ - serviceID: AuthV2.ServiceID.make("gitlab"), - credential: new AuthV2.ApiKeyCredential({ type: "api", key: "auth-token" }), - active: true, + const accounts = yield* AccountV2.Service + const catalog = yield* Catalog.Service + const events = yield* EventV2.Service + yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("gitlab"), + credential: new AccountV2.ApiKeyCredential({ type: "api", key: "account-token" }), }) yield* plugin.add({ - ...AuthPlugin, - effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + ...AccountPlugin, + effect: AccountPlugin.effect.pipe( + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(EventV2.Service, events), + Effect.provideService(PluginV2.Service, plugin), + ), }) yield* plugin.add(GitLabPlugin) - const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("gitlab"), cancel: false }) + const load = yield* catalog.loader() + yield* load((catalog) => catalog.provider.update(ProviderV2.ID.make("gitlab"), () => {})) + const provider = yield* catalog.provider.get(ProviderV2.ID.make("gitlab")) yield* plugin.trigger( "aisdk.sdk", { model: model("gitlab", "claude"), package: "gitlab-ai-provider", - options: updated.provider.options.aisdk.provider, + options: provider.options.aisdk.provider, }, {}, ) - expect(gitlabSDKOptions[0].apiKey).toBe("auth-token") + expect(gitlabSDKOptions[0].apiKey).toBe("account-token") }), ), ) - itWithAuth.effect("uses active OAuth access token when no API auth exists", () => + itWithAccount.effect("uses active account OAuth access token when no API token exists", () => withEnv( { GITLAB_TOKEN: undefined, @@ -185,33 +205,41 @@ describe("GitLabPlugin", () => { Effect.gen(function* () { gitlabSDKOptions.length = 0 const plugin = yield* PluginV2.Service - const auth = yield* AuthV2.Service - yield* auth.create({ - serviceID: AuthV2.ServiceID.make("gitlab"), - credential: new AuthV2.OAuthCredential({ + const accounts = yield* AccountV2.Service + const catalog = yield* Catalog.Service + const events = yield* EventV2.Service + yield* accounts.create({ + serviceID: AccountV2.ServiceID.make("gitlab"), + credential: new AccountV2.OAuthCredential({ type: "oauth", refresh: "refresh-token", - access: "oauth-token", + access: "account-oauth-token", expires: 9999999999999, }), - active: true, }) yield* plugin.add({ - ...AuthPlugin, - effect: AuthPlugin.effect.pipe(Effect.provideService(AuthV2.Service, auth)), + ...AccountPlugin, + effect: AccountPlugin.effect.pipe( + Effect.provideService(AccountV2.Service, accounts), + Effect.provideService(Catalog.Service, catalog), + Effect.provideService(EventV2.Service, events), + Effect.provideService(PluginV2.Service, plugin), + ), }) yield* plugin.add(GitLabPlugin) - const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("gitlab"), cancel: false }) + const load = yield* catalog.loader() + yield* load((catalog) => catalog.provider.update(ProviderV2.ID.make("gitlab"), () => {})) + const provider = yield* catalog.provider.get(ProviderV2.ID.make("gitlab")) yield* plugin.trigger( "aisdk.sdk", { model: model("gitlab", "claude"), package: "gitlab-ai-provider", - options: updated.provider.options.aisdk.provider, + options: provider.options.aisdk.provider, }, {}, ) - expect(gitlabSDKOptions[0].apiKey).toBe("oauth-token") + expect(gitlabSDKOptions[0].apiKey).toBe("account-oauth-token") }), ), ) diff --git a/packages/core/test/plugin/provider-google-vertex-anthropic.test.ts b/packages/core/test/plugin/provider-google-vertex-anthropic.test.ts index 6bcece53c9..7cb2b24ffd 100644 --- a/packages/core/test/plugin/provider-google-vertex-anthropic.test.ts +++ b/packages/core/test/plugin/provider-google-vertex-anthropic.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" -import { GoogleVertexAnthropicPlugin } from "@opencode-ai/core/plugin/provider/google-vertex" -import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" +import { GoogleVertexAnthropicPlugin, GoogleVertexPlugin } from "@opencode-ai/core/plugin/provider/google-vertex" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { fakeSelectorSdk, it, model, withEnv } from "./provider-helper" describe("GoogleVertexAnthropicPlugin", () => { it.effect("resolves legacy project and location env on provider update", () => @@ -18,14 +20,17 @@ describe("GoogleVertexAnthropicPlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexAnthropicPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("google-vertex-anthropic"), cancel: false }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex-anthropic"), (provider) => { + provider.endpoint = { type: "aisdk", package: "@ai-sdk/google-vertex/anthropic" } + }), ) - expect(result.provider.options.aisdk.provider.project).toBe("cloud-project") - expect(result.provider.options.aisdk.provider.location).toBe("cloud-location") + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")) + expect(provider.options.aisdk.provider.project).toBe("cloud-project") + expect(provider.options.aisdk.provider.location).toBe("cloud-location") }), ), ) @@ -34,23 +39,19 @@ describe("GoogleVertexAnthropicPlugin", () => { withEnv({ GOOGLE_CLOUD_PROJECT: "env-project", GOOGLE_CLOUD_LOCATION: "env-location" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexAnthropicPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("google-vertex-anthropic", { - options: { - headers: {}, - body: {}, - aisdk: { provider: { project: "configured-project", location: "configured-location" }, request: {} }, - }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex-anthropic"), (provider) => { + provider.endpoint = { type: "aisdk", package: "@ai-sdk/google-vertex/anthropic" } + provider.options.aisdk.provider.project = "configured-project" + provider.options.aisdk.provider.location = "configured-location" + }), ) - expect(result.provider.options.aisdk.provider.project).toBe("configured-project") - expect(result.provider.options.aisdk.provider.location).toBe("configured-location") + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex-anthropic")) + expect(provider.options.aisdk.provider.project).toBe("configured-project") + expect(provider.options.aisdk.provider.location).toBe("configured-location") }), ), ) @@ -108,6 +109,73 @@ describe("GoogleVertexAnthropicPlugin", () => { ), ) + it.effect("creates SDKs for google-vertex Anthropic models with multi-region endpoints", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", "claude-sonnet-4-5"), + package: "@ai-sdk/google-vertex/anthropic", + options: { name: "google-vertex", project: "project", location: "eu" }, + }, + {}, + ) + expect(result.sdk.languageModel("claude-sonnet-4-5").config.baseURL).toBe( + "https://aiplatform.eu.rep.googleapis.com/v1/projects/project/locations/eu/publishers/anthropic/models", + ) + }), + ) + + it.effect("keeps configured baseURL for google-vertex Anthropic models", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexAnthropicPlugin) + const result = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", "claude-sonnet-4-5"), + package: "@ai-sdk/google-vertex/anthropic", + options: { name: "google-vertex", project: "project", location: "eu", baseURL: "https://proxy.example/v1" }, + }, + {}, + ) + expect(result.sdk.languageModel("claude-sonnet-4-5").config.baseURL).toBe("https://proxy.example/v1") + }), + ) + + it.effect("selects google-vertex Anthropic language models through V2 plugins", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + yield* plugin.add(GoogleVertexPlugin) + yield* plugin.add(GoogleVertexAnthropicPlugin) + const sdkResult = yield* plugin.trigger( + "aisdk.sdk", + { + model: model("google-vertex", " claude-sonnet-4-5 "), + package: "@ai-sdk/google-vertex/anthropic", + options: { name: "google-vertex", project: "project", location: "us" }, + }, + {}, + ) + const languageResult = yield* plugin.trigger( + "aisdk.language", + { + model: model("google-vertex", " claude-sonnet-4-5 "), + sdk: sdkResult.sdk, + options: {}, + }, + {}, + ) + const language = languageResult.language as unknown as { config: { baseURL: string }; modelId: string } + expect(language.config.baseURL).toBe( + "https://aiplatform.us.rep.googleapis.com/v1/projects/project/locations/us/publishers/anthropic/models", + ) + expect(language.modelId).toBe("claude-sonnet-4-5") + }), + ) + it.effect("trims model IDs before selecting language models", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service diff --git a/packages/core/test/plugin/provider-google-vertex.test.ts b/packages/core/test/plugin/provider-google-vertex.test.ts index 3bd60fd721..2a9a18875c 100644 --- a/packages/core/test/plugin/provider-google-vertex.test.ts +++ b/packages/core/test/plugin/provider-google-vertex.test.ts @@ -1,8 +1,10 @@ import { describe, expect, mock } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { GoogleVertexPlugin } from "@opencode-ai/core/plugin/provider/google-vertex" -import { fakeSelectorSdk, it, model, provider, withEnv } from "./provider-helper" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { fakeSelectorSdk, it, model, withEnv } from "./provider-helper" const vertexOptions: Record[] = [] @@ -43,24 +45,22 @@ describe("GoogleVertexPlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("google-vertex", { - endpoint: { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", - }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", + } + }), ) - expect(result.provider.options.aisdk.provider.project).toBe("google-cloud-project") - expect(result.provider.options.aisdk.provider.location).toBe("google-vertex-location") - expect(result.provider.endpoint).toEqual({ + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")) + expect(provider.options.aisdk.provider.project).toBe("google-cloud-project") + expect(provider.options.aisdk.provider.location).toBe("google-vertex-location") + expect(provider.endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://google-vertex-location-aiplatform.googleapis.com/v1/projects/google-cloud-project/locations/google-vertex-location", @@ -84,21 +84,19 @@ describe("GoogleVertexPlugin", () => { Effect.gen(function* () { vertexOptions.length = 0 const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexPlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("google-vertex", { - endpoint: { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", - }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", + } + }), ) + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")) yield* plugin.trigger( "aisdk.sdk", { @@ -111,8 +109,8 @@ describe("GoogleVertexPlugin", () => { {}, ) - expect(updated.provider.options.aisdk.provider.project).toBe("vertex-project") - expect(updated.provider.endpoint).toEqual({ + expect(provider.options.aisdk.provider.project).toBe("vertex-project") + expect(provider.endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://europe-west4-aiplatform.googleapis.com/v1/projects/vertex-project/locations/europe-west4", @@ -136,29 +134,24 @@ describe("GoogleVertexPlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("google-vertex", { - endpoint: { - type: "aisdk", - package: "@ai-sdk/openai-compatible", - url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", - }, - options: { - headers: {}, - body: {}, - aisdk: { provider: { project: "config-project", location: "global" }, request: {} }, - }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", + } + provider.options.aisdk.provider.project = "config-project" + provider.options.aisdk.provider.location = "global" + }), ) - expect(result.provider.options.aisdk.provider.project).toBe("config-project") - expect(result.provider.options.aisdk.provider.location).toBe("global") - expect(result.provider.endpoint).toEqual({ + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")) + expect(provider.options.aisdk.provider.project).toBe("config-project") + expect(provider.options.aisdk.provider.location).toBe("global") + expect(provider.endpoint).toEqual({ type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://aiplatform.googleapis.com/v1/projects/config-project/locations/global", @@ -167,6 +160,32 @@ describe("GoogleVertexPlugin", () => { ), ) + it.effect("keeps OpenAI-compatible Vertex endpoint templates regional for eu", () => + Effect.gen(function* () { + const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service + yield* plugin.add(GoogleVertexPlugin) + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => { + provider.endpoint = { + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://${GOOGLE_VERTEX_ENDPOINT}/v1/projects/${GOOGLE_VERTEX_PROJECT}/locations/${GOOGLE_VERTEX_LOCATION}", + } + provider.options.aisdk.provider.project = "config-project" + provider.options.aisdk.provider.location = "eu" + }), + ) + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")) + expect(provider.endpoint).toEqual({ + type: "aisdk", + package: "@ai-sdk/openai-compatible", + url: "https://eu-aiplatform.googleapis.com/v1/projects/config-project/locations/eu", + }) + }), + ) + it.effect("defaults location to us-central1 when only project is configured", () => withEnv( { @@ -180,19 +199,18 @@ describe("GoogleVertexPlugin", () => { () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(GoogleVertexPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("google-vertex", { - options: { headers: {}, body: {}, aisdk: { provider: { project: "config-project" }, request: {} } }, - }), - cancel: false, - }, + const load = yield* catalog.loader() + yield* load((catalog) => + catalog.provider.update(ProviderV2.ID.make("google-vertex"), (provider) => { + provider.endpoint = { type: "aisdk", package: "@ai-sdk/google-vertex" } + provider.options.aisdk.provider.project = "config-project" + }), ) - expect(result.provider.options.aisdk.provider.project).toBe("config-project") - expect(result.provider.options.aisdk.provider.location).toBe("us-central1") + const provider = yield* catalog.provider.get(ProviderV2.ID.make("google-vertex")) + expect(provider.options.aisdk.provider.project).toBe("config-project") + expect(provider.options.aisdk.provider.location).toBe("us-central1") }), ), ) diff --git a/packages/core/test/plugin/provider-helper.ts b/packages/core/test/plugin/provider-helper.ts index 0d67075ac8..1b8f1c65a0 100644 --- a/packages/core/test/plugin/provider-helper.ts +++ b/packages/core/test/plugin/provider-helper.ts @@ -2,12 +2,16 @@ import { Npm } from "@opencode-ai/core/npm" import type { LanguageModelV3 } from "@ai-sdk/provider" import { expect } from "bun:test" import { Effect, Layer, Option } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +import { EventV2 } from "@opencode-ai/core/event" +import { Location } from "@opencode-ai/core/location" import { ModelV2 } from "@opencode-ai/core/model" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderV2 } from "@opencode-ai/core/provider" import { testEffect } from "../lib/effect" export const fixtureProvider = new URL("./fixtures/provider-factory.ts", import.meta.url).href +const locationLayer = Layer.succeed(Location.Service, Location.Service.of({ directory: "test" })) export const npmLayer = Layer.succeed( Npm.Service, @@ -18,7 +22,34 @@ export const npmLayer = Layer.succeed( }), ) -export const it = testEffect(Layer.mergeAll(PluginV2.defaultLayer, npmLayer)) +export const catalogLayer = Layer.succeed( + Catalog.Service, + Catalog.Service.of({ + loader: () => Effect.die("unexpected catalog.loader"), + provider: { + get: () => Effect.die("unexpected provider.get"), + all: () => Effect.succeed([]), + available: () => Effect.succeed([]), + }, + model: { + get: () => Effect.die("unexpected model.get"), + all: () => Effect.succeed([]), + available: () => Effect.succeed([]), + default: () => Effect.succeed(Option.none()), + setDefault: () => Effect.die("unexpected model.setDefault"), + small: () => Effect.succeed(Option.none()), + }, + }), +) + +export const it = testEffect( + Catalog.layer.pipe( + Layer.provideMerge(PluginV2.defaultLayer), + Layer.provideMerge(EventV2.defaultLayer), + Layer.provideMerge(locationLayer), + Layer.provideMerge(npmLayer), + ), +) export function provider(providerID: string, options?: Partial) { return new ProviderV2.Info({ diff --git a/packages/core/test/plugin/provider-kilo.test.ts b/packages/core/test/plugin/provider-kilo.test.ts index 4261ae1328..cafe4c10f6 100644 --- a/packages/core/test/plugin/provider-kilo.test.ts +++ b/packages/core/test/plugin/provider-kilo.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { KiloPlugin } from "@opencode-ai/core/plugin/provider/kilo" +import { ProviderV2 } from "@opencode-ai/core/provider" import { expectPluginRegistered, it, provider } from "./provider-helper" describe("KiloPlugin", () => { @@ -18,73 +20,81 @@ describe("KiloPlugin", () => { it.effect("applies legacy referer headers only to kilo", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(KiloPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("kilo", { - options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - const ignored = yield* plugin.trigger("provider.update", {}, { provider: provider("openrouter"), cancel: false }) - expect(result.provider.options.headers).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const kilo = provider("kilo", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://api.kilo.ai/api/gateway" }, + options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(kilo.id, (draft) => { + draft.endpoint = kilo.endpoint + draft.options = kilo.options + }) + catalog.provider.update(provider("openrouter").id, () => {}) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo"))).options.headers).toEqual({ Existing: "value", "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", }) - expect(ignored.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.openrouter)).options.headers).toEqual({}) }), ) it.effect("uses the exact legacy Kilo header casing and set", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(KiloPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("kilo"), cancel: false }) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("kilo", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://api.kilo.ai/api/gateway" }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + }) + }) - expect(result.provider.options.headers).toEqual({ + const result = yield* catalog.provider.get(ProviderV2.ID.make("kilo")) + expect(result.options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", }) - expect(result.provider.options.headers).not.toHaveProperty("http-referer") - expect(result.provider.options.headers).not.toHaveProperty("x-title") - expect(result.provider.options.headers).not.toHaveProperty("X-Source") + expect(result.options.headers).not.toHaveProperty("http-referer") + expect(result.options.headers).not.toHaveProperty("x-title") + expect(result.options.headers).not.toHaveProperty("X-Source") }), ) it.effect("uses the legacy provider-id guard instead of endpoint package matching", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(KiloPlugin) - const matchingID = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("kilo", { - endpoint: { type: "aisdk", package: "not-kilo" }, - }), - cancel: false, - }, - ) - const matchingPackage = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("custom-kilo", { - endpoint: { type: "aisdk", package: "kilo" }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const kilo = provider("kilo", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://api.kilo.ai/api/gateway" }, + }) + catalog.provider.update(kilo.id, (draft) => { + draft.endpoint = kilo.endpoint + }) + const custom = provider("custom-kilo", { + endpoint: { type: "aisdk", package: "kilo" }, + }) + catalog.provider.update(custom.id, (draft) => { + draft.endpoint = custom.endpoint + }) + }) - expect(matchingID.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("kilo"))).options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", }) - expect(matchingPackage.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.make("custom-kilo"))).options.headers).toEqual({}) }), ) }) diff --git a/packages/core/test/plugin/provider-llmgateway.test.ts b/packages/core/test/plugin/provider-llmgateway.test.ts index 1ffea96bcb..f34b7b3fcc 100644 --- a/packages/core/test/plugin/provider-llmgateway.test.ts +++ b/packages/core/test/plugin/provider-llmgateway.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { LLMGatewayPlugin } from "@opencode-ai/core/plugin/provider/llmgateway" +import { ProviderV2 } from "@opencode-ai/core/provider" import { expectPluginRegistered, it, provider } from "./provider-helper" describe("LLMGatewayPlugin", () => { @@ -18,46 +20,54 @@ describe("LLMGatewayPlugin", () => { it.effect("applies legacy referer headers only to enabled llmgateway", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(LLMGatewayPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("llmgateway", { - enabled: { via: "env", name: "LLMGATEWAY_API_KEY" }, - options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - const ignored = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("openrouter", { - enabled: { via: "env", name: "OPENROUTER_API_KEY" }, - }), - cancel: false, - }, - ) - expect(result.provider.options.headers).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const llmgateway = provider("llmgateway", { + enabled: { via: "env", name: "LLMGATEWAY_API_KEY" }, + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://api.llmgateway.io/v1" }, + options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(llmgateway.id, (draft) => { + draft.enabled = llmgateway.enabled + draft.endpoint = llmgateway.endpoint + draft.options = llmgateway.options + }) + const openrouter = provider("openrouter", { + enabled: { via: "env", name: "OPENROUTER_API_KEY" }, + }) + catalog.provider.update(openrouter.id, (draft) => { + draft.enabled = openrouter.enabled + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway"))).options.headers).toEqual({ Existing: "value", "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", "X-Source": "opencode", }) - expect(ignored.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.openrouter)).options.headers).toEqual({}) }), ) it.effect("does not apply legacy headers to a disabled llmgateway provider", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(LLMGatewayPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("llmgateway"), cancel: false }) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("llmgateway", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://api.llmgateway.io/v1" }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + }) + }) - expect(result.provider.enabled).toBe(false) - expect(result.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway"))).enabled).toBe(false) + expect((yield* catalog.provider.get(ProviderV2.ID.make("llmgateway"))).options.headers).toEqual({}) }), ) }) diff --git a/packages/core/test/plugin/provider-nvidia.test.ts b/packages/core/test/plugin/provider-nvidia.test.ts index 26e7db0bfb..8bd9051bd8 100644 --- a/packages/core/test/plugin/provider-nvidia.test.ts +++ b/packages/core/test/plugin/provider-nvidia.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { NvidiaPlugin } from "@opencode-ai/core/plugin/provider/nvidia" +import { ProviderV2 } from "@opencode-ai/core/provider" import { expectPluginRegistered, it, provider } from "./provider-helper" describe("NvidiaPlugin", () => { @@ -18,45 +20,48 @@ describe("NvidiaPlugin", () => { it.effect("applies NVIDIA tracking headers only to nvidia", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(NvidiaPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("nvidia", { - options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - const ignored = yield* plugin.trigger("provider.update", {}, { provider: provider("openrouter"), cancel: false }) - expect(result.provider.options.headers).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const nvidia = provider("nvidia", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://integrate.api.nvidia.com/v1" }, + options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(nvidia.id, (draft) => { + draft.endpoint = nvidia.endpoint + draft.options = nvidia.options + }) + catalog.provider.update(provider("openrouter").id, () => {}) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia"))).options.headers).toEqual({ Existing: "value", "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", "X-BILLING-INVOKE-ORIGIN": "OpenCode", }) - expect(ignored.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.openrouter)).options.headers).toEqual({}) }), ) it.effect("adds billing origin for custom NVIDIA endpoints", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(NvidiaPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("nvidia", { - endpoint: { type: "aisdk", package: "test-provider", url: "http://localhost:8000/v1" }, - options: { headers: {}, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("nvidia", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://integrate.api.nvidia.com/v1" }, + options: { headers: {}, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) - expect(result.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia"))).options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", "X-BILLING-INVOKE-ORIGIN": "OpenCode", @@ -67,23 +72,25 @@ describe("NvidiaPlugin", () => { it.effect("preserves an explicit NVIDIA billing origin header", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(NvidiaPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("nvidia", { - options: { - headers: { "X-BILLING-INVOKE-ORIGIN": "CustomOrigin" }, - body: {}, - aisdk: { provider: { baseURL: "https://integrate.api.nvidia.com/v1" }, request: {} }, - }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("nvidia", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://integrate.api.nvidia.com/v1" }, + options: { + headers: { "X-BILLING-INVOKE-ORIGIN": "CustomOrigin" }, + body: {}, + aisdk: { provider: { baseURL: "https://integrate.api.nvidia.com/v1" }, request: {} }, + }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) - expect(result.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia"))).options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", "X-BILLING-INVOKE-ORIGIN": "CustomOrigin", diff --git a/packages/core/test/plugin/provider-openai.test.ts b/packages/core/test/plugin/provider-openai.test.ts index 31d6dd0b6d..93e451e018 100644 --- a/packages/core/test/plugin/provider-openai.test.ts +++ b/packages/core/test/plugin/provider-openai.test.ts @@ -1,9 +1,11 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { ModelV2 } from "@opencode-ai/core/model" import { PluginV2 } from "@opencode-ai/core/plugin" import { OpenAIPlugin } from "@opencode-ai/core/plugin/provider/openai" -import { fakeSelectorSdk, it, model } from "./provider-helper" +import { ProviderV2 } from "@opencode-ai/core/provider" +import { fakeSelectorSdk, it, model, provider } from "./provider-helper" describe("OpenAIPlugin", () => { it.effect("creates an OpenAI SDK for @ai-sdk/openai using the provider ID as SDK name", () => @@ -70,31 +72,39 @@ describe("OpenAIPlugin", () => { }), ) - it.effect("cancels gpt-5-chat-latest during model updates", () => + it.effect("disables gpt-5-chat-latest during catalog transforms", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpenAIPlugin) - const normal = yield* plugin.trigger("model.update", {}, { model: model("openai", "gpt-5"), cancel: false }) - const filtered = yield* plugin.trigger( - "model.update", - {}, - { model: model("openai", "gpt-5-chat-latest"), cancel: false }, - ) - expect(normal.cancel).toBe(false) - expect(filtered.cancel).toBe(true) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("openai", { endpoint: { type: "aisdk", package: "@ai-sdk/openai" } }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + }) + catalog.model.update(item.id, ModelV2.ID.make("gpt-5"), () => {}) + catalog.model.update(item.id, ModelV2.ID.make("gpt-5-chat-latest"), () => {}) + }) + expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5"))).enabled).toBe(true) + expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("gpt-5-chat-latest"))).enabled).toBe(false) }), ) - it.effect("does not cancel gpt-5-chat-latest for non-OpenAI providers", () => + it.effect("does not disable gpt-5-chat-latest for non-OpenAI providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpenAIPlugin) - const result = yield* plugin.trigger( - "model.update", - {}, - { model: model("custom-openai", "gpt-5-chat-latest"), cancel: false }, - ) - expect(result.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("custom-openai") + catalog.provider.update(item.id, () => {}) + catalog.model.update(item.id, ModelV2.ID.make("gpt-5-chat-latest"), () => {}) + }) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("custom-openai"), ModelV2.ID.make("gpt-5-chat-latest"))).enabled, + ).toBe(true) }), ) }) diff --git a/packages/core/test/plugin/provider-opencode.test.ts b/packages/core/test/plugin/provider-opencode.test.ts index ed82686a21..3f59a34977 100644 --- a/packages/core/test/plugin/provider-opencode.test.ts +++ b/packages/core/test/plugin/provider-opencode.test.ts @@ -12,19 +12,23 @@ const cost = (input: number, output = 0) => [{ input, output, cache: { read: 0, const locationLayer = Layer.succeed(Location.Service, Location.Service.of({ directory: "test" })) describe("OpencodePlugin", () => { - it.effect("uses a public key and cancels paid models without credentials", () => + it.effect("uses a public key and disables paid models without credentials", () => withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("opencode"), cancel: false }) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBe("public") - expect(paid.cancel).toBe(true) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode") + catalog.provider.update(item.id, () => {}) + const paid = model("opencode", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBe("public") + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(false) }), ), ) @@ -33,14 +37,19 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - yield* plugin.trigger("provider.update", {}, { provider: provider("opencode"), cancel: false }) - const free = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "free", { cost: cost(0) }), cancel: false }, - ) - expect(free.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode") + catalog.provider.update(item.id, () => {}) + const free = model("opencode", "free", { cost: cost(0) }) + catalog.model.update(item.id, free.id, (draft) => { + draft.cost = [...free.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBe("public") + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("free"))).enabled).toBe(true) }), ), ) @@ -49,14 +58,19 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - yield* plugin.trigger("provider.update", {}, { provider: provider("opencode"), cancel: false }) - const outputOnly = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "output-only", { cost: cost(0, 1) }), cancel: false }, - ) - expect(outputOnly.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode") + catalog.provider.update(item.id, () => {}) + const outputOnly = model("opencode", "output-only", { cost: cost(0, 1) }) + catalog.model.update(item.id, outputOnly.id, (draft) => { + draft.cost = [...outputOnly.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBe("public") + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("output-only"))).enabled).toBe(true) }), ), ) @@ -65,15 +79,19 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: "secret" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("opencode"), cancel: false }) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBeUndefined() - expect(paid.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode") + catalog.provider.update(item.id, () => {}) + const paid = model("opencode", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBeUndefined() + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true) }), ), ) @@ -82,19 +100,21 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined, CUSTOM_OPENCODE_API_KEY: "secret" }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("opencode", { env: ["CUSTOM_OPENCODE_API_KEY"] }), cancel: false }, - ) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBeUndefined() - expect(paid.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode", { env: ["CUSTOM_OPENCODE_API_KEY"] }) + catalog.provider.update(item.id, (draft) => { + draft.env = [...item.env] + }) + const paid = model("opencode", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBeUndefined() + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true) }), ), ) @@ -103,31 +123,30 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("opencode", { - options: { - headers: {}, - body: {}, - aisdk: { - provider: { apiKey: "configured" }, - request: {}, - }, + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode", { + options: { + headers: {}, + body: {}, + aisdk: { + provider: { apiKey: "configured" }, + request: {}, }, - }), - cancel: false, - }, - ) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBe("configured") - expect(paid.cancel).toBe(false) + }, + }) + catalog.provider.update(item.id, (draft) => { + draft.options = item.options + }) + const paid = model("opencode", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBe("configured") + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true) }), ), ) @@ -136,19 +155,21 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger( - "provider.update", - {}, - { provider: provider("opencode", { enabled: { via: "auth", service: "opencode" } }), cancel: false }, - ) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("opencode", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBeUndefined() - expect(paid.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("opencode", { enabled: { via: "account", service: "opencode" } }) + catalog.provider.update(item.id, (draft) => { + draft.enabled = item.enabled + }) + const paid = model("opencode", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.opencode)).options.aisdk.provider.apiKey).toBeUndefined() + expect((yield* catalog.model.get(ProviderV2.ID.opencode, ModelV2.ID.make("paid"))).enabled).toBe(true) }), ), ) @@ -157,15 +178,19 @@ describe("OpencodePlugin", () => { withEnv({ OPENCODE_API_KEY: undefined }, () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpencodePlugin) - const updated = yield* plugin.trigger("provider.update", {}, { provider: provider("openai"), cancel: false }) - const paid = yield* plugin.trigger( - "model.update", - {}, - { model: model("openai", "paid", { cost: cost(1) }), cancel: false }, - ) - expect(updated.provider.options.aisdk.provider.apiKey).toBeUndefined() - expect(paid.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("openai") + catalog.provider.update(item.id, () => {}) + const paid = model("openai", "paid", { cost: cost(1) }) + catalog.model.update(item.id, paid.id, (draft) => { + draft.cost = [...paid.cost] + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.openai)).options.aisdk.provider.apiKey).toBeUndefined() + expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("paid"))).enabled).toBe(true) }), ), ) @@ -175,18 +200,21 @@ describe("OpencodePlugin", () => { const catalog = yield* Catalog.Service const providerID = ProviderV2.ID.opencode - yield* catalog.provider.update(providerID, () => {}) - yield* catalog.model.update(providerID, ModelV2.ID.make("cheap-mini"), (model) => { - model.capabilities.input = ["text"] - model.capabilities.output = ["text"] - model.cost = cost(1, 1) - model.time.released = DateTime.makeUnsafe(Date.now()) - }) - yield* catalog.model.update(providerID, ModelV2.ID.make("gpt-5-nano"), (model) => { - model.capabilities.input = ["text"] - model.capabilities.output = ["text"] - model.cost = cost(10, 10) - model.time.released = DateTime.makeUnsafe(Date.now()) + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(providerID, () => {}) + catalog.model.update(providerID, ModelV2.ID.make("cheap-mini"), (model) => { + model.capabilities.input = ["text"] + model.capabilities.output = ["text"] + model.cost = [...cost(1, 1)] + model.time.released = DateTime.makeUnsafe(Date.now()) + }) + catalog.model.update(providerID, ModelV2.ID.make("gpt-5-nano"), (model) => { + model.capabilities.input = ["text"] + model.capabilities.output = ["text"] + model.cost = [...cost(10, 10)] + model.time.released = DateTime.makeUnsafe(Date.now()) + }) }) const selected = yield* catalog.model.small(providerID) diff --git a/packages/core/test/plugin/provider-openrouter.test.ts b/packages/core/test/plugin/provider-openrouter.test.ts index 3d143ac7f2..a60323b8d3 100644 --- a/packages/core/test/plugin/provider-openrouter.test.ts +++ b/packages/core/test/plugin/provider-openrouter.test.ts @@ -1,8 +1,11 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" +import { ModelV2 } from "@opencode-ai/core/model" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { OpenRouterPlugin } from "@opencode-ai/core/plugin/provider/openrouter" +import { ProviderV2 } from "@opencode-ai/core/provider" import { expectPluginRegistered, it, model, provider } from "./provider-helper" describe("OpenRouterPlugin", () => { @@ -18,24 +21,27 @@ describe("OpenRouterPlugin", () => { it.effect("applies legacy referer headers only to openrouter", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpenRouterPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("openrouter", { - options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - const ignored = yield* plugin.trigger("provider.update", {}, { provider: provider("nvidia"), cancel: false }) - expect(result.provider.options.headers).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const openrouter = provider("openrouter", { + endpoint: { type: "aisdk", package: "@openrouter/ai-sdk-provider" }, + options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(openrouter.id, (item) => { + item.endpoint = openrouter.endpoint + item.options = openrouter.options + }) + catalog.provider.update(ProviderV2.ID.make("nvidia"), () => {}) + }) + + expect((yield* catalog.provider.get(ProviderV2.ID.make("openrouter"))).options.headers).toEqual({ Existing: "value", "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", }) - expect(ignored.provider.options.headers).toEqual({}) + expect((yield* catalog.provider.get(ProviderV2.ID.make("nvidia"))).options.headers).toEqual({}) }), ) @@ -67,39 +73,50 @@ describe("OpenRouterPlugin", () => { it.effect("filters OpenRouter's gpt-5 chat alias", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpenRouterPlugin) - const result = yield* plugin.trigger( - "model.update", - {}, - { model: model("openrouter", "openai/gpt-5-chat"), cancel: false }, - ) - const regular = yield* plugin.trigger( - "model.update", - {}, - { model: model("openrouter", "openai/gpt-5"), cancel: false }, - ) - const ignored = yield* plugin.trigger( - "model.update", - {}, - { model: model("openai", "openai/gpt-5-chat"), cancel: false }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const openrouter = provider("openrouter", { + endpoint: { type: "aisdk", package: "@openrouter/ai-sdk-provider" }, + }) + catalog.provider.update(openrouter.id, (item) => { + item.endpoint = openrouter.endpoint + }) + catalog.provider.update(ProviderV2.ID.openai, () => {}) + for (const item of [ + model("openrouter", "openai/gpt-5-chat"), + model("openrouter", "openai/gpt-5"), + model("openai", "openai/gpt-5-chat"), + ]) { + catalog.model.update(item.providerID, item.id, () => {}) + } + }) - expect(result.cancel).toBe(true) - expect(regular.cancel).toBe(false) - expect(ignored.cancel).toBe(false) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("openrouter"), ModelV2.ID.make("openai/gpt-5-chat"))).enabled, + ).toBe(false) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("openrouter"), ModelV2.ID.make("openai/gpt-5"))).enabled, + ).toBe(true) + expect((yield* catalog.model.get(ProviderV2.ID.openai, ModelV2.ID.make("openai/gpt-5-chat"))).enabled).toBe(true) }), ) - it.effect("does not filter gpt-5-chat-latest for non-OpenRouter providers", () => + it.effect("does not disable gpt-5-chat-latest for non-OpenRouter providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(OpenRouterPlugin) - const result = yield* plugin.trigger( - "model.update", - {}, - { model: model("custom-openrouter", "gpt-5-chat-latest"), cancel: false }, - ) - expect(result.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + catalog.provider.update(ProviderV2.ID.make("custom-openrouter"), () => {}) + catalog.model.update(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest"), () => {}) + }) + expect( + (yield* catalog.model.get(ProviderV2.ID.make("custom-openrouter"), ModelV2.ID.make("gpt-5-chat-latest"))) + .enabled, + ).toBe(true) }), ) }) diff --git a/packages/core/test/plugin/provider-vercel.test.ts b/packages/core/test/plugin/provider-vercel.test.ts index 3134a7b83c..f6d9efd192 100644 --- a/packages/core/test/plugin/provider-vercel.test.ts +++ b/packages/core/test/plugin/provider-vercel.test.ts @@ -1,25 +1,29 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { VercelPlugin } from "@opencode-ai/core/plugin/provider/vercel" +import { ProviderV2 } from "@opencode-ai/core/provider" import { it, model, provider } from "./provider-helper" describe("VercelPlugin", () => { it.effect("applies legacy lower-case referer headers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(VercelPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("vercel", { - options: { headers: { Existing: "1" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) - expect(result.provider.options.headers).toEqual({ + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("vercel", { + endpoint: { type: "aisdk", package: "@ai-sdk/vercel" }, + options: { headers: { Existing: "1" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel"))).options.headers).toEqual({ Existing: "1", "http-referer": "https://opencode.ai/", "x-title": "opencode", @@ -30,10 +34,19 @@ describe("VercelPlugin", () => { it.effect("does not add legacy upper-case referer headers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(VercelPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("vercel"), cancel: false }) - expect(result.provider.options.headers).not.toHaveProperty("HTTP-Referer") - expect(result.provider.options.headers).not.toHaveProperty("X-Title") + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("vercel", { endpoint: { type: "aisdk", package: "@ai-sdk/vercel" } }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + }) + }) + expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel"))).options.headers).not.toHaveProperty( + "HTTP-Referer", + ) + expect((yield* catalog.provider.get(ProviderV2.ID.make("vercel"))).options.headers).not.toHaveProperty("X-Title") }), ) @@ -54,9 +67,11 @@ describe("VercelPlugin", () => { it.effect("ignores non-Vercel providers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(VercelPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("gateway"), cancel: false }) - expect(result.provider.options.headers).toEqual({}) + const load = yield* catalog.loader() + yield* load((catalog) => catalog.provider.update(provider("gateway").id, () => {})) + expect((yield* catalog.provider.get(ProviderV2.ID.make("gateway"))).options.headers).toEqual({}) }), ) }) diff --git a/packages/core/test/plugin/provider-zenmux.test.ts b/packages/core/test/plugin/provider-zenmux.test.ts index 2b7730e6c7..71067a5a1e 100644 --- a/packages/core/test/plugin/provider-zenmux.test.ts +++ b/packages/core/test/plugin/provider-zenmux.test.ts @@ -1,8 +1,10 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { Catalog } from "@opencode-ai/core/catalog" import { PluginV2 } from "@opencode-ai/core/plugin" import { ProviderPlugins } from "@opencode-ai/core/plugin/provider" import { ZenmuxPlugin } from "@opencode-ai/core/plugin/provider/zenmux" +import { ProviderV2 } from "@opencode-ai/core/provider" import { expectPluginRegistered, it, provider } from "./provider-helper" describe("ZenmuxPlugin", () => { @@ -18,30 +20,41 @@ describe("ZenmuxPlugin", () => { it.effect("applies the exact legacy Zenmux headers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(ZenmuxPlugin) - const result = yield* plugin.trigger("provider.update", {}, { provider: provider("zenmux"), cancel: false }) - expect(result.provider.options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode" }) - expect(Object.keys(result.provider.options.headers).sort()).toEqual(["HTTP-Referer", "X-Title"]) - expect(result.cancel).toBe(false) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("zenmux", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://zenmux.ai/api/v1" }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + }) + }) + const result = yield* catalog.provider.get(ProviderV2.ID.make("zenmux")) + expect(result.options.headers).toEqual({ "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode" }) + expect(Object.keys(result.options.headers).sort()).toEqual(["HTTP-Referer", "X-Title"]) }), ) it.effect("merges legacy Zenmux headers with existing headers", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(ZenmuxPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("zenmux", { - options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("zenmux", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://zenmux.ai/api/v1" }, + options: { headers: { Existing: "value" }, body: {}, aisdk: { provider: {}, request: {} } }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) - expect(result.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("zenmux"))).options.headers).toEqual({ Existing: "value", "HTTP-Referer": "https://opencode.ai/", "X-Title": "opencode", @@ -52,23 +65,25 @@ describe("ZenmuxPlugin", () => { it.effect("lets configured Zenmux legacy headers override defaults", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(ZenmuxPlugin) - const result = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("zenmux", { - options: { - headers: { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }, - body: {}, - aisdk: { provider: {}, request: {} }, - }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("zenmux", { + endpoint: { type: "aisdk", package: "@ai-sdk/openai-compatible", url: "https://zenmux.ai/api/v1" }, + options: { + headers: { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }, + body: {}, + aisdk: { provider: {}, request: {} }, + }, + }) + catalog.provider.update(item.id, (draft) => { + draft.endpoint = item.endpoint + draft.options = item.options + }) + }) - expect(result.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.make("zenmux"))).options.headers).toEqual({ "HTTP-Referer": "https://example.com/", "X-Title": "custom-title", }) @@ -78,23 +93,23 @@ describe("ZenmuxPlugin", () => { it.effect("guards legacy Zenmux headers to the exact zenmux provider id", () => Effect.gen(function* () { const plugin = yield* PluginV2.Service + const catalog = yield* Catalog.Service yield* plugin.add(ZenmuxPlugin) - const ignored = yield* plugin.trigger( - "provider.update", - {}, - { - provider: provider("openrouter", { - options: { - headers: { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }, - body: {}, - aisdk: { provider: {}, request: {} }, - }, - }), - cancel: false, - }, - ) + const load = yield* catalog.loader() + yield* load((catalog) => { + const item = provider("openrouter", { + options: { + headers: { "HTTP-Referer": "https://example.com/", "X-Title": "custom-title" }, + body: {}, + aisdk: { provider: {}, request: {} }, + }, + }) + catalog.provider.update(item.id, (draft) => { + draft.options = item.options + }) + }) - expect(ignored.provider.options.headers).toEqual({ + expect((yield* catalog.provider.get(ProviderV2.ID.openrouter)).options.headers).toEqual({ "HTTP-Referer": "https://example.com/", "X-Title": "custom-title", }) diff --git a/packages/effect-drizzle-sqlite/AGENTS.md b/packages/effect-drizzle-sqlite/AGENTS.md new file mode 100644 index 0000000000..39010a1127 --- /dev/null +++ b/packages/effect-drizzle-sqlite/AGENTS.md @@ -0,0 +1,19 @@ +# Effect Drizzle SQLite + +This package vendors a Drizzle Effect SQLite adapter for this repo. + +- Keep this package generic: Drizzle + Effect + SQLite only. +- Do not add opencode-specific tables, paths, migrations, post-commit hooks, or domain storage APIs here. +- Runtime code should depend on generic `effect/unstable/sql/SqlClient`, not a specific SQLite driver. +- Concrete SQLite clients such as `@effect/sql-sqlite-bun` belong in tests or examples unless this package intentionally adds a driver-specific helper. +- Preserve Drizzle adapter naming and behavior where possible so this can be replaced by upstream `drizzle-orm/effect-sqlite` later. +- If touching copied Drizzle internals, compare with current `drizzle-orm@1.0.0-rc.2` declarations and runtime JS. +- If touching Effect APIs, verify against `/Users/kit/code/open-source/effect-smol`. + +Useful entry points: + +- `src/effect-sqlite/driver.ts`: creates the Effect-backed Drizzle database with `make` and `makeWithDefaults`. +- `src/effect-sqlite/session.ts`: adapts generic Effect `SqlClient` execution and transactions to Drizzle SQLite sessions. +- `src/sqlite-core/effect/*`: Effect-yieldable SQLite query builders. +- `src/internal/drizzle-utils.ts`: local typed shims for Drizzle runtime internals that RC2 does not expose in declarations. +- `examples/basic.ts`: minimal usage example with Bun SQLite. diff --git a/packages/effect-drizzle-sqlite/examples/basic.ts b/packages/effect-drizzle-sqlite/examples/basic.ts new file mode 100644 index 0000000000..675aabcb85 --- /dev/null +++ b/packages/effect-drizzle-sqlite/examples/basic.ts @@ -0,0 +1,92 @@ +import { SqliteClient } from "@effect/sql-sqlite-bun" +import { eq } from "drizzle-orm" +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core" +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Schema from "effect/Schema" +import { EffectDrizzleSqlite } from "../src" + +const users = sqliteTable("users", { + id: integer().primaryKey({ autoIncrement: true }), + name: text().notNull(), +}) + +type User = typeof users.$inferSelect + +const makeDatabase = EffectDrizzleSqlite.makeWithDefaults() +type DatabaseShape = Effect.Success + +const sqliteLayer = SqliteClient.layer({ filename: ":memory:", disableWAL: true }) + +class Database extends Context.Service()("@opencode/example/Database") { + static layer = Layer.effect(Database, makeDatabase).pipe(Layer.provide(sqliteLayer)) +} + +class UserStoreError extends Schema.TaggedErrorClass()("UserStoreError", { + message: Schema.String, + cause: Schema.optional(Schema.Defect), +}) {} + +const mapStoreError = (message: string) => (cause: unknown) => new UserStoreError({ message, cause }) + +interface UserStoreShape { + migrate(): Effect.Effect + create(name: string): Effect.Effect + rename(from: string, to: string): Effect.Effect + list(): Effect.Effect +} + +class UserStore extends Context.Service()("@opencode/example/UserStore") { + static layer = Layer.effect( + UserStore, + Effect.gen(function* () { + const db = yield* Database + + return UserStore.of({ + migrate: Effect.fn("UserStore.migrate")(function* () { + yield* EffectDrizzleSqlite.migrate(db, { migrationsFolder: `${import.meta.dirname}/migrations` }).pipe( + Effect.mapError((cause) => new UserStoreError({ message: "Failed to migrate users", cause })), + ) + }), + create: Effect.fn("UserStore.create")(function* (name: string) { + yield* db + .insert(users) + .values({ name }) + .pipe(Effect.asVoid, Effect.mapError(mapStoreError("Failed to create user"))) + }), + rename: Effect.fn("UserStore.rename")(function* (from: string, to: string) { + yield* db + .transaction( + Effect.fnUntraced(function* (tx) { + yield* tx.insert(users).values({ name: from }) + yield* tx.update(users).set({ name: to }).where(eq(users.name, from)) + }), + { behavior: "immediate" }, + ) + .pipe(Effect.asVoid, Effect.mapError(mapStoreError("Failed to rename user"))) + }), + list: Effect.fn("UserStore.list")(function* () { + return yield* db + .select() + .from(users) + .pipe(Effect.mapError(mapStoreError("Failed to list users"))) + }), + }) + }), + ).pipe(Layer.provide(Database.layer)) +} + +const program = Effect.gen(function* () { + const userStore = yield* UserStore + + yield* userStore.migrate() + yield* userStore.create("Ada") + yield* userStore.rename("Grace", "Grace Hopper") + + return yield* userStore.list() +}) + +const rows = await Effect.runPromise(program.pipe(Effect.provide(UserStore.layer))) + +console.log(rows) diff --git a/packages/effect-drizzle-sqlite/examples/migrations/20240101000000_create_users/migration.sql b/packages/effect-drizzle-sqlite/examples/migrations/20240101000000_create_users/migration.sql new file mode 100644 index 0000000000..f1aa81cb45 --- /dev/null +++ b/packages/effect-drizzle-sqlite/examples/migrations/20240101000000_create_users/migration.sql @@ -0,0 +1,4 @@ +CREATE TABLE users ( + id integer PRIMARY KEY AUTOINCREMENT NOT NULL, + name text NOT NULL +); diff --git a/packages/effect-drizzle-sqlite/package.json b/packages/effect-drizzle-sqlite/package.json new file mode 100644 index 0000000000..8009f40c70 --- /dev/null +++ b/packages/effect-drizzle-sqlite/package.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "version": "7.3.46", + "name": "@opencode-ai/effect-drizzle-sqlite", + "type": "module", + "license": "MIT", + "private": true, + "scripts": { + "test": "bun test --timeout 30000", + "test:ci": "mkdir -p .artifacts/unit && bun test --timeout 30000 --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml", + "typecheck": "tsgo --noEmit" + }, + "exports": { + ".": "./src/index.ts", + "./effect-sqlite": "./src/effect-sqlite/index.ts", + "./effect-sqlite/migrator": "./src/effect-sqlite/migrator.ts", + "./sqlite-core/effect": "./src/sqlite-core/effect/index.ts" + }, + "devDependencies": { + "@effect/sql-sqlite-bun": "catalog:", + "@tsconfig/bun": "catalog:", + "@types/bun": "catalog:", + "@typescript/native-preview": "catalog:" + }, + "dependencies": { + "drizzle-orm": "catalog:", + "effect": "catalog:" + } +} diff --git a/packages/effect-drizzle-sqlite/src/effect-sqlite/driver.ts b/packages/effect-drizzle-sqlite/src/effect-sqlite/driver.ts new file mode 100644 index 0000000000..f2ffc207d3 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/effect-sqlite/driver.ts @@ -0,0 +1,77 @@ +/* oxlint-disable */ +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import { SqlClient } from "effect/unstable/sql/SqlClient" +import { EffectCache } from "drizzle-orm/cache/core/cache-effect" +import { EffectLogger } from "drizzle-orm/effect-core" +import { entityKind } from "drizzle-orm/entity" +import type { AnyRelations, EmptyRelations } from "drizzle-orm/relations" +import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" +import { SQLiteEffectDatabase } from "../sqlite-core/effect/db" +import type { DrizzleConfig } from "drizzle-orm/utils" +import { jitCompatCheck } from "../internal/drizzle-utils" +import { type EffectSQLiteQueryEffectHKT, type EffectSQLiteRunResult, EffectSQLiteSession } from "./session" + +export class EffectSQLiteDatabase extends SQLiteEffectDatabase< + EffectSQLiteQueryEffectHKT, + EffectSQLiteRunResult, + TRelations +> { + static override readonly [entityKind]: string = "EffectSQLiteDatabase" +} + +export type EffectDrizzleSQLiteConfig = Omit< + DrizzleConfig, TRelations>, + "cache" | "logger" | "schema" +> + +export const DefaultServices = Layer.merge(EffectCache.Default, EffectLogger.Default) + +/** + * Creates an EffectSQLiteDatabase instance. + * + * Requires a generic Effect `SqlClient`, `EffectLogger`, and `EffectCache` services to be provided. + * Drizzle only depends on the generic `SqlClient`; install and provide a compatible SQLite provider such as + * `@effect/sql-sqlite-node`, `@effect/sql-sqlite-bun`, or another package that exposes `SqlClient`. + * + * @example + * ```ts + * import { SqliteClient } from '@effect/sql-sqlite-node'; + * import * as SQLiteDrizzle from 'drizzle-orm/effect-sqlite'; + * import * as Effect from 'effect/Effect'; + * + * const db = yield* SQLiteDrizzle.make({ relations }).pipe( + * Effect.provide(SQLiteDrizzle.DefaultServices), + * Effect.provide(SqliteClient.layer({ filename: 'sqlite.db' })), + * ); + * ``` + */ +export const make = Effect.fn("SQLiteDrizzle.make")(function* ( + config: EffectDrizzleSQLiteConfig = {}, +) { + const client = yield* SqlClient + const cache = yield* EffectCache + const logger = yield* EffectLogger + + const dialect = new SQLiteAsyncDialect() + const relations = config.relations ?? ({} as TRelations) + const session = new EffectSQLiteSession(client, dialect, relations, { + logger, + cache, + useJitMappers: jitCompatCheck(config.jit), + }) + const db = new EffectSQLiteDatabase(dialect, session, relations) as EffectSQLiteDatabase & { + $client: SqlClient + } + db.$client = client + db.$cache.invalidate = cache.onMutate + + return db +}) + +/** + * Convenience function that creates an EffectSQLiteDatabase with `DefaultServices` already provided. + */ +export const makeWithDefaults = ( + config: EffectDrizzleSQLiteConfig = {}, +) => make(config).pipe(Effect.provide(DefaultServices)) diff --git a/packages/effect-drizzle-sqlite/src/effect-sqlite/index.ts b/packages/effect-drizzle-sqlite/src/effect-sqlite/index.ts new file mode 100644 index 0000000000..1133e48b3a --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/effect-sqlite/index.ts @@ -0,0 +1,4 @@ +/* oxlint-disable */ +export { EffectLogger } from "drizzle-orm/effect-core" +export * from "./driver" +export * from "./session" diff --git a/packages/effect-drizzle-sqlite/src/effect-sqlite/migrator.ts b/packages/effect-drizzle-sqlite/src/effect-sqlite/migrator.ts new file mode 100644 index 0000000000..6d0d155143 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/effect-sqlite/migrator.ts @@ -0,0 +1,14 @@ +/* oxlint-disable */ +import type { MigrationConfig } from "drizzle-orm/migrator" +import { readMigrationFiles } from "drizzle-orm/migrator" +import type { AnyRelations } from "drizzle-orm/relations" +import { migrate as coreMigrate } from "../sqlite-core/effect/session" +import type { EffectSQLiteDatabase } from "./driver" + +export function migrate( + db: EffectSQLiteDatabase, + config: MigrationConfig, +) { + const migrations = readMigrationFiles(config) + return coreMigrate(migrations, db.session, config) +} diff --git a/packages/effect-drizzle-sqlite/src/effect-sqlite/session.ts b/packages/effect-drizzle-sqlite/src/effect-sqlite/session.ts new file mode 100644 index 0000000000..047b50b61f --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/effect-sqlite/session.ts @@ -0,0 +1,214 @@ +/* oxlint-disable */ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import * as Scope from "effect/Scope" +import type { SqlClient } from "effect/unstable/sql/SqlClient" +import type { SqlError } from "effect/unstable/sql/SqlError" +import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" +import type { WithCacheConfig } from "drizzle-orm/cache/core/types" +import type { EffectDrizzleQueryError } from "drizzle-orm/effect-core/errors" +import type { EffectLoggerShape } from "drizzle-orm/effect-core/logger" +import type { QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import type { AnyRelations } from "drizzle-orm/relations" +import type { RelationalQueryMapperConfig } from "drizzle-orm/relations" +import type { Query } from "drizzle-orm/sql/sql" +import type { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" +import { SQLiteEffectPreparedQuery, SQLiteEffectSession, SQLiteEffectTransaction } from "../sqlite-core/effect/session" +import type { SelectedFieldsOrdered } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { PreparedQueryConfig, SQLiteExecuteMethod, SQLiteTransactionConfig } from "drizzle-orm/sqlite-core/session" + +export interface EffectSQLiteQueryEffectHKT extends QueryEffectHKTBase { + readonly error: EffectDrizzleQueryError + readonly context: never +} + +export type EffectSQLiteRunResult = readonly never[] + +export interface EffectSQLiteSessionOptions { + logger: EffectLoggerShape + cache: EffectCacheShape + useJitMappers?: boolean +} + +export class EffectSQLiteSession extends SQLiteEffectSession< + EffectSQLiteQueryEffectHKT, + EffectSQLiteRunResult, + TRelations +> { + static override readonly [entityKind]: string = "EffectSQLiteSession" + + constructor( + private client: SqlClient, + dialect: SQLiteAsyncDialect, + protected relations: TRelations, + private options: EffectSQLiteSessionOptions, + ) { + super(dialect) + } + + override prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, + queryMetadata?: { + type: "select" | "update" | "delete" | "insert" + tables: string[] + }, + cacheConfig?: WithCacheConfig, + ): SQLiteEffectPreparedQuery { + return new SQLiteEffectPreparedQuery( + (params, method) => this.execute(query, params, method), + query, + this.options.logger, + this.options.cache, + queryMetadata, + cacheConfig, + fields, + executeMethod, + this.options.useJitMappers, + customResultMapper, + undefined, + undefined, + this.isInTransaction(), + ) + } + + override prepareRelationalQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper: (rows: Record[], mapColumnValue?: (value: unknown) => unknown) => unknown, + config: RelationalQueryMapperConfig, + ): SQLiteEffectPreparedQuery { + return new SQLiteEffectPreparedQuery( + (params, method) => this.execute(query, params, method), + query, + this.options.logger, + this.options.cache, + undefined, + undefined, + fields, + executeMethod, + this.options.useJitMappers, + customResultMapper, + true, + config, + this.isInTransaction(), + ) + } + + private execute(query: Query, params: unknown[], method: SQLiteExecuteMethod | "values") { + const statement = this.client.unsafe(query.sql, params) + if (method === "values") return statement.values + if (method === "get") return statement.withoutTransform.pipe(Effect.map((rows) => rows[0])) + return statement.withoutTransform + } + + private isInTransaction() { + return Effect.serviceOption(this.client.transactionService).pipe(Effect.map((option) => option._tag === "Some")) + } + + private executeTransactionStatement(connection: Effect.Success, query: string) { + return connection.executeUnprepared(query, [], undefined).pipe(Effect.asVoid) + } + + private withTransaction(effect: Effect.Effect, config: SQLiteTransactionConfig | undefined) { + return Effect.uninterruptibleMask((restore) => + Effect.withFiber((fiber) => { + const services = fiber.context + const connectionOption = Context.getOption(services, this.client.transactionService) + const connection: Effect.Effect< + readonly [Scope.Closeable | undefined, Effect.Success], + SqlError + > = + connectionOption._tag === "Some" + ? Effect.succeed([undefined, connectionOption.value[0]] as const) + : Scope.make().pipe( + Effect.flatMap((scope) => + Scope.provide(this.client.reserve, scope).pipe( + Effect.map((connection) => [scope, connection] as const), + Effect.catch((error) => + Scope.close(scope, Exit.fail(error)).pipe(Effect.andThen(Effect.fail(error))), + ), + ), + ), + ) + const id = connectionOption._tag === "Some" ? connectionOption.value[1] + 1 : 0 + + return connection.pipe( + Effect.flatMap(([scope, connection]) => + this.executeTransactionStatement( + connection, + id === 0 ? `begin ${config?.behavior ?? "deferred"}` : `savepoint effect_sql_${id}`, + ).pipe( + Effect.flatMap(() => + Effect.provideContext( + restore(effect), + Context.add(services, this.client.transactionService, [connection, id]), + ), + ), + Effect.exit, + Effect.flatMap((exit) => { + const finalize = Exit.isSuccess(exit) + ? id === 0 + ? this.executeTransactionStatement(connection, "commit").pipe( + // SQLite keeps the transaction open after deferred constraint commit failures. + Effect.catch((error) => + this.executeTransactionStatement(connection, "rollback").pipe( + Effect.catch(() => Effect.void), + Effect.andThen(Effect.fail(error)), + ), + ), + ) + : this.executeTransactionStatement(connection, `release savepoint effect_sql_${id}`) + : id === 0 + ? this.executeTransactionStatement(connection, "rollback") + : this.executeTransactionStatement(connection, `rollback to savepoint effect_sql_${id}`).pipe( + Effect.andThen( + this.executeTransactionStatement(connection, `release savepoint effect_sql_${id}`), + ), + ) + const scoped = scope === undefined ? finalize : Effect.ensuring(finalize, Scope.close(scope, exit)) + + return scoped.pipe(Effect.flatMap(() => exit)) + }), + ), + ), + ) + }), + ) + } + + override transaction( + transaction: (tx: EffectSQLiteTransaction) => Effect.Effect, + config?: SQLiteTransactionConfig, + ): Effect.Effect { + const { dialect, relations } = this + + return this.withTransaction( + Effect.gen({ self: this }, function* () { + const tx = new EffectSQLiteTransaction(dialect, this, relations) + + return yield* transaction(tx) + }), + config, + ) + } +} + +export class EffectSQLiteTransaction extends SQLiteEffectTransaction< + EffectSQLiteQueryEffectHKT, + EffectSQLiteRunResult, + TRelations +> { + static override readonly [entityKind]: string = "EffectSQLiteTransaction" + + override transaction: ( + transaction: ( + tx: SQLiteEffectTransaction, + ) => Effect.Effect, + ) => Effect.Effect = (tx) => this.session.transaction(tx) +} diff --git a/packages/effect-drizzle-sqlite/src/index.ts b/packages/effect-drizzle-sqlite/src/index.ts new file mode 100644 index 0000000000..d6606b7d9f --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/index.ts @@ -0,0 +1,6 @@ +export { EffectLogger } from "drizzle-orm/effect-core" +export * from "./effect-sqlite/driver" +export * from "./effect-sqlite/session" +export { migrate } from "./effect-sqlite/migrator" + +export * as EffectDrizzleSqlite from "." diff --git a/packages/effect-drizzle-sqlite/src/internal/drizzle-utils.ts b/packages/effect-drizzle-sqlite/src/internal/drizzle-utils.ts new file mode 100644 index 0000000000..1998a08318 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/internal/drizzle-utils.ts @@ -0,0 +1,127 @@ +/* oxlint-disable */ +import { Column, getColumnTable } from "drizzle-orm/column" +import { is } from "drizzle-orm/entity" +import type { JoinNullability } from "drizzle-orm/query-builders/select.types" +import { Param, SQL } from "drizzle-orm/sql/sql" +import type { SelectedFieldsOrdered } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { SQLiteUpdateSetSource } from "drizzle-orm/sqlite-core/query-builders/update" +import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import { SQLiteViewBase } from "drizzle-orm/sqlite-core/view-base" +import { Subquery } from "drizzle-orm/subquery" +import { Table, getTableName } from "drizzle-orm/table" +import type { UpdateSet } from "drizzle-orm/utils" +import { ViewBaseConfig } from "drizzle-orm/view-common" + +const TableSymbol = ( + Table as unknown as { + Symbol: { Columns: symbol; IsAlias: symbol; Name: symbol; BaseName: symbol } + } +).Symbol + +export function getTableColumnsRuntime(table: SQLiteTable) { + return (table as unknown as Record>)[TableSymbol.Columns] +} + +export function getViewSelectedFieldsRuntime(view: SQLiteViewBase) { + return (view as unknown as Record; name: string }>)[ViewBaseConfig] +} + +export function jitCompatCheck(isEnabled: boolean | undefined) { + if (!isEnabled) return false + try { + return new Function("input", '"use strict"; return input;')(true) === true + } catch { + return false + } +} + +export function orderSelectedFields( + fields: Record, + pathPrefix?: string[], +): SelectedFieldsOrdered { + return Object.entries(fields).flatMap(([name, field]) => { + const path = pathPrefix ? [...pathPrefix, name] : [name] + if (is(field, Column) || is(field, SQL) || is(field, SQL.Aliased) || is(field, Subquery)) { + return [{ path, field }] as SelectedFieldsOrdered + } + if (is(field, Table)) return orderSelectedFields(getTableColumnsRuntime(field as SQLiteTable), path) + return orderSelectedFields(field as Record, path) + }) as SelectedFieldsOrdered +} + +export function mapUpdateSet(table: TTable, values: SQLiteUpdateSetSource) { + const entries = Object.entries(values).filter(([, value]) => value !== undefined) + if (entries.length === 0) throw new Error("No values to set") + + return Object.fromEntries( + entries.map(([key, value]) => [ + key, + is(value, SQL) || is(value, Column) ? value : new Param(value, getTableColumnsRuntime(table)[key]), + ]), + ) as UpdateSet +} + +export function mapResultRow( + columns: SelectedFieldsOrdered, + row: unknown[], + joinsNotNullableMap: Record | undefined, +) { + const nullifyMap: Record = {} + const result: Record = {} + + columns.forEach((column, columnIndex) => { + const decoder = ( + is(column.field, Column) + ? column.field + : is(column.field, SQL) + ? (column.field as unknown as { decoder: { mapFromDriverValue(value: unknown): unknown } }).decoder + : is(column.field, Subquery) + ? (column.field._.sql as unknown as { decoder: { mapFromDriverValue(value: unknown): unknown } }).decoder + : (column.field.sql as unknown as { decoder: { mapFromDriverValue(value: unknown): unknown } }).decoder + ) as { + mapFromDriverValue(value: unknown): unknown + } + const rawValue = row[columnIndex] + const value = rawValue === null ? null : decoder.mapFromDriverValue(rawValue) + const objectName = column.path[0] + let node = result + + column.path.forEach((pathChunk, pathChunkIndex) => { + if (pathChunkIndex === column.path.length - 1) { + node[pathChunk] = value + return + } + node[pathChunk] = (node[pathChunk] ?? {}) as Record + node = node[pathChunk] as Record + }) + + if (joinsNotNullableMap && is(column.field, Column) && column.path.length === 2 && objectName) { + const tableName = getTableName(getColumnTable(column.field)) + nullifyMap[objectName] = + !(objectName in nullifyMap) && value === null + ? tableName + : typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== tableName + ? false + : nullifyMap[objectName] + } + }) + + Object.entries(nullifyMap).forEach(([objectName, tableName]) => { + if (typeof tableName === "string" && !joinsNotNullableMap?.[tableName]) result[objectName] = null + }) + + return result +} + +export function getTableLikeName(table: SQLiteTable | Subquery | SQLiteViewBase | SQL) { + if (is(table, Subquery)) return table._.alias + if (is(table, SQLiteViewBase)) return getViewSelectedFieldsRuntime(table).name + if (is(table, SQL)) return undefined + return (table as unknown as Record)[ + (table as unknown as Record)[TableSymbol.IsAlias] + ? TableSymbol.Name + : TableSymbol.BaseName + ] as string +} + +export type { JoinNullability } diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/count.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/count.ts new file mode 100644 index 0000000000..c420d6fbb0 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/count.ts @@ -0,0 +1,58 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import { SQL, sql, type SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import type { SQLiteView } from "drizzle-orm/sqlite-core/view" +import type { SQLiteEffectSession } from "./session" + +function buildSQLiteEmbeddedCount(source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL) { + return sql`(select count(*) from ${source}${sql.raw(" where ").if(filters)}${filters})` +} + +function buildSQLiteCount(source: SQLiteTable | SQLiteView | SQL | SQLWrapper, filters?: SQL) { + return sql`select count(*) from ${source}${sql.raw(" where ").if(filters)}${filters}` +} + +export interface SQLiteEffectCountBuilder + extends SQL, + SQLWrapper, + Effect.Effect {} + +export class SQLiteEffectCountBuilder extends SQL { + static override readonly [entityKind]: string = "SQLiteEffectCountBuilder" + + private sql: SQL + private session: SQLiteEffectSession + + constructor(params: { + source: SQLiteTable | SQLiteView | SQL | SQLWrapper + filters?: SQL + session: SQLiteEffectSession + }) { + super(buildSQLiteEmbeddedCount(params.source, params.filters).queryChunks) + + this.session = params.session + this.sql = buildSQLiteCount(params.source, params.filters) + } + + execute(placeholderValues?: Record) { + return this.session + .prepareQuery<{ + type: "async" + execute: number + run: unknown + all: unknown + get: unknown + values: unknown + }>(this.session.dialect.sqlToQuery(this.sql), undefined, "all", (rows) => { + const v = rows[0]?.[0] + if (typeof v === "number") return v + return v ? Number(v) : 0 + }) + .execute(placeholderValues) + } +} + +applyEffectWrapper(SQLiteEffectCountBuilder) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/db.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/db.ts new file mode 100644 index 0000000000..ac4cc140ad --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/db.ts @@ -0,0 +1,296 @@ +/* oxlint-disable */ +import { Effect } from "effect" +import type { SqlError } from "effect/unstable/sql/SqlError" +import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" +import type { MutationOption } from "drizzle-orm/cache/core/cache" +import type { QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import type { TypedQueryBuilder } from "drizzle-orm/query-builders/query-builder" +import type { AnyRelations, EmptyRelations } from "drizzle-orm/relations" +import { SelectionProxyHandler } from "drizzle-orm/selection-proxy" +import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" +import { QueryBuilder } from "drizzle-orm/sqlite-core/query-builders/query-builder" +import type { SelectedFields } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { SQLiteTransactionConfig } from "drizzle-orm/sqlite-core/session" +import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import type { SQLiteViewBase } from "drizzle-orm/sqlite-core/view-base" +import { WithSubquery } from "drizzle-orm/subquery" +import type { WithBuilder } from "drizzle-orm/sqlite-core/subquery" +import { SQLiteEffectCountBuilder } from "./count" +import { SQLiteEffectDeleteBase } from "./delete" +import { SQLiteEffectInsertBuilder } from "./insert" +import { SQLiteEffectRelationalQueryBuilder } from "./query" +import { SQLiteEffectRaw } from "./raw" +import { SQLiteEffectSelectBuilder } from "./select" +import type { SQLiteEffectSelectBase } from "./select" +import type { SQLiteEffectSession, SQLiteEffectTransaction } from "./session" +import { SQLiteEffectUpdateBuilder } from "./update" + +export class SQLiteEffectDatabase< + TEffectHKT extends QueryEffectHKTBase, + TRunResult, + TRelations extends AnyRelations = EmptyRelations, +> { + static readonly [entityKind]: string = "SQLiteEffectDatabase" + + declare readonly _: { + readonly relations: TRelations + readonly session: SQLiteEffectSession + } + + query: { + [K in keyof TRelations]: SQLiteEffectRelationalQueryBuilder + } + + constructor( + /** @internal */ + readonly dialect: SQLiteAsyncDialect, + /** @internal */ + readonly session: SQLiteEffectSession, + relations: TRelations, + readonly rowModeRQB?: boolean, + readonly forbidJsonb?: boolean, + ) { + this._ = { + relations, + session, + } + + this.query = {} as (typeof this)["query"] + for (const [tableName, relation] of Object.entries(relations)) { + ;(this.query as SQLiteEffectDatabase["query"])[tableName] = + new SQLiteEffectRelationalQueryBuilder( + relations, + relations[relation.name]!.table as SQLiteTable, + relation, + dialect, + session, + rowModeRQB, + forbidJsonb, + ) + } + + this.$cache = { + invalidate: (_params: MutationOption) => Effect.void, + } + } + + $with: WithBuilder = (alias: string, selection?: ColumnsSelection) => { + const self = this + const as = ( + qb: + | TypedQueryBuilder + | SQL + | ((qb: QueryBuilder) => TypedQueryBuilder | SQL), + ) => { + if (typeof qb === "function") { + qb = qb(new QueryBuilder(self.dialect)) + } + + return new Proxy( + new WithSubquery( + qb.getSQL(), + selection ?? + (("getSelectedFields" in qb + ? ((qb as { getSelectedFields(): SelectedFields | undefined }).getSelectedFields() ?? {}) + : {}) as SelectedFields), + alias, + true, + ), + new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" }), + ) + } + return { as } + } + + $cache: { invalidate: EffectCacheShape["onMutate"] } + + $count(source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL) { + return new SQLiteEffectCountBuilder({ source, filters, session: this.session }) + } + + with(...queries: WithSubquery[]) { + const self = this + + function select(): SQLiteEffectSelectBuilder + function select( + fields: TSelection, + ): SQLiteEffectSelectBuilder + function select( + fields?: SelectedFields, + ): SQLiteEffectSelectBuilder { + return new SQLiteEffectSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + }) + } + + function selectDistinct(): SQLiteEffectSelectBuilder + function selectDistinct( + fields: TSelection, + ): SQLiteEffectSelectBuilder + function selectDistinct( + fields?: SelectedFields, + ): SQLiteEffectSelectBuilder { + return new SQLiteEffectSelectBuilder({ + fields: fields ?? undefined, + session: self.session, + dialect: self.dialect, + withList: queries, + distinct: true, + }) + } + + function update( + table: TTable, + ): SQLiteEffectUpdateBuilder { + return new SQLiteEffectUpdateBuilder(table, self.session, self.dialect, queries) + } + + function insert( + into: TTable, + ): SQLiteEffectInsertBuilder { + return new SQLiteEffectInsertBuilder(into, self.session, self.dialect, queries) + } + + function delete_( + from: TTable, + ): SQLiteEffectDeleteBase { + return new SQLiteEffectDeleteBase(from, self.session, self.dialect, queries) + } + + return { select, selectDistinct, update, insert, delete: delete_ } + } + + select(): SQLiteEffectSelectBuilder + select( + fields: TSelection, + ): SQLiteEffectSelectBuilder + select(fields?: SelectedFields): SQLiteEffectSelectBuilder { + return new SQLiteEffectSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }) + } + + selectDistinct(): SQLiteEffectSelectBuilder + selectDistinct( + fields: TSelection, + ): SQLiteEffectSelectBuilder + selectDistinct( + fields?: SelectedFields, + ): SQLiteEffectSelectBuilder { + return new SQLiteEffectSelectBuilder({ + fields: fields ?? undefined, + session: this.session, + dialect: this.dialect, + distinct: true, + }) + } + + update(table: TTable): SQLiteEffectUpdateBuilder { + return new SQLiteEffectUpdateBuilder(table, this.session, this.dialect) + } + + insert(into: TTable): SQLiteEffectInsertBuilder { + return new SQLiteEffectInsertBuilder(into, this.session, this.dialect) + } + + delete( + from: TTable, + ): SQLiteEffectDeleteBase { + return new SQLiteEffectDeleteBase(from, this.session, this.dialect) + } + + private raw( + query: SQLWrapper | string, + action: "all" | "get" | "run" | "values", + execute: (query: SQL) => Effect.Effect, + ): SQLiteEffectRaw { + const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL() + return new SQLiteEffectRaw( + () => execute(sequel), + () => sequel, + action, + this.dialect, + (result) => result, + ) + } + + run(query: SQLWrapper | string): SQLiteEffectRaw { + return this.raw(query, "run", (sequel) => this.session.run(sequel)) + } + + all(query: SQLWrapper | string): SQLiteEffectRaw { + return this.raw(query, "all", (sequel) => this.session.all(sequel)) + } + + get(query: SQLWrapper | string): SQLiteEffectRaw { + return this.raw(query, "get", (sequel) => this.session.get(sequel)) + } + + values(query: SQLWrapper | string): SQLiteEffectRaw { + return this.raw(query, "values", (sequel) => this.session.values(sequel)) + } + + transaction: ( + transaction: (tx: SQLiteEffectTransaction) => Effect.Effect, + config?: SQLiteTransactionConfig, + ) => Effect.Effect = (tx, config) => this.session.transaction(tx, config) +} + +export type SQLiteEffectWithReplicas = Q & { $primary: Q; $replicas: Q[] } + +export const withReplicas = < + TEffectHKT extends QueryEffectHKTBase, + TRunResult, + TRelations extends AnyRelations, + Q extends SQLiteEffectDatabase, +>( + primary: Q, + replicas: [Q, ...Q[]], + getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, +): SQLiteEffectWithReplicas => { + const select: Q["select"] = (...args: []) => getReplica(replicas).select(...args) + const selectDistinct: Q["selectDistinct"] = (...args: []) => getReplica(replicas).selectDistinct(...args) + const $count: Q["$count"] = (...args: [any]) => getReplica(replicas).$count(...args) + const _with: Q["with"] = (...args: []) => getReplica(replicas).with(...args) + const $with = ((...args: [string] | [string, ColumnsSelection]) => + args.length === 1 + ? getReplica(replicas).$with(args[0]) + : getReplica(replicas).$with(args[0], args[1])) as Q["$with"] + + const update: Q["update"] = (...args: [any]) => primary.update(...args) + const insert: Q["insert"] = (...args: [any]) => primary.insert(...args) + const $delete: Q["delete"] = (...args: [any]) => primary.delete(...args) + const run: Q["run"] = (...args: [any]) => primary.run(...args) + const all: Q["all"] = (...args: [any]) => primary.all(...args) + const get: Q["get"] = (...args: [any]) => primary.get(...args) + const values: Q["values"] = (...args: [any]) => primary.values(...args) + const transaction: Q["transaction"] = (...args: [any]) => primary.transaction(...args) + + return { + ...primary, + update, + insert, + delete: $delete, + run, + all, + get, + values, + transaction, + $primary: primary, + $replicas: replicas, + select, + selectDistinct, + $count, + $with, + with: _with, + get query() { + return getReplica(replicas).query + }, + } +} + +export type AnySQLiteEffectDatabase = SQLiteEffectDatabase +export type AnySQLiteEffectSelectBase = SQLiteEffectSelectBase diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/delete.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/delete.ts new file mode 100644 index 0000000000..15e90d1974 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/delete.ts @@ -0,0 +1,261 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import type { SelectResultFields } from "drizzle-orm/query-builders/select.types" +import type { RunnableQuery } from "drizzle-orm/runnable-query" +import { SelectionProxyHandler } from "drizzle-orm/selection-proxy" +import type { Placeholder, Query, SQL, SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect" +import type { SQLiteDeleteConfig } from "drizzle-orm/sqlite-core/query-builders/delete" +import type { SelectedFieldsFlat } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { PreparedQueryConfig } from "drizzle-orm/sqlite-core/session" +import { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import { extractUsedTable } from "drizzle-orm/sqlite-core/utils" +import type { Subquery } from "drizzle-orm/subquery" +import { type DrizzleTypeError, type ValueOrArray } from "drizzle-orm/utils" +import type { SQLiteColumn } from "drizzle-orm/sqlite-core/columns/common" +import { getTableColumnsRuntime, orderSelectedFields } from "../../internal/drizzle-utils" +import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session" + +export type SQLiteEffectDeleteWithout< + T extends AnySQLiteEffectDelete, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true + ? T + : Omit< + SQLiteEffectDeleteBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["returning"], + TDynamic, + T["_"]["excludedMethods"] | K, + T["_"]["effectHKT"] + >, + T["_"]["excludedMethods"] | K + > + +export type SQLiteEffectDeleteReturningAll< + T extends AnySQLiteEffectDelete, + TDynamic extends boolean, +> = SQLiteEffectDeleteWithout< + SQLiteEffectDeleteBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["table"]["$inferSelect"], + T["_"]["dynamic"], + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectDeleteReturning< + T extends AnySQLiteEffectDelete, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = SQLiteEffectDeleteWithout< + SQLiteEffectDeleteBase< + T["_"]["table"], + T["_"]["runResult"], + SelectResultFields, + T["_"]["dynamic"], + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectDeleteExecute = T["_"]["returning"] extends undefined + ? T["_"]["runResult"] + : T["_"]["returning"][] + +export type SQLiteEffectDeletePrepare< + T extends AnySQLiteEffectDelete, + TEffectHKT extends QueryEffectHKTBase = T["_"]["effectHKT"], +> = SQLiteEffectPreparedQuery< + PreparedQueryConfig & { + run: T["_"]["runResult"] + all: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".all() cannot be used without .returning()"> + : T["_"]["returning"][] + get: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".get() cannot be used without .returning()"> + : T["_"]["returning"] | undefined + values: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".values() cannot be used without .returning()"> + : any[][] + execute: SQLiteEffectDeleteExecute + }, + TEffectHKT +> + +export type SQLiteEffectDeleteDynamic = SQLiteEffectDelete< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["returning"], + T["_"]["effectHKT"] +> + +export type SQLiteEffectDelete< + TTable extends SQLiteTable = SQLiteTable, + TRunResult = unknown, + TReturning extends Record | undefined = undefined, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> = SQLiteEffectDeleteBase + +export type AnySQLiteEffectDelete = SQLiteEffectDeleteBase + +export interface SQLiteEffectDeleteBase< + TTable extends SQLiteTable, + TRunResult, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> extends RunnableQuery, + SQLWrapper, + Effect.Effect< + TReturning extends undefined ? TRunResult : TReturning[], + TEffectHKT["error"], + TEffectHKT["context"] + > { + readonly _: { + dialect: "sqlite" + readonly table: TTable + readonly resultType: "async" + readonly runResult: TRunResult + readonly returning: TReturning + readonly dynamic: TDynamic + readonly excludedMethods: _TExcludedMethods + readonly result: TReturning extends undefined ? TRunResult : TReturning[] + readonly effectHKT: TEffectHKT + } +} + +export class SQLiteEffectDeleteBase< + TTable extends SQLiteTable, + TRunResult, + TReturning extends Record | undefined = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + > + implements RunnableQuery, SQLWrapper +{ + static readonly [entityKind]: string = "SQLiteEffectDelete" + + /** @internal */ + config: SQLiteDeleteConfig + + constructor( + private table: TTable, + private effectSession: SQLiteEffectSession, + private effectDialect: SQLiteDialect, + withList?: Subquery[], + ) { + this.config = { table, withList } + } + + where(where: SQL | undefined): SQLiteEffectDeleteWithout { + this.config.where = where + return this as any + } + + orderBy( + builder: (deleteTable: TTable) => ValueOrArray, + ): SQLiteEffectDeleteWithout + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteEffectDeleteWithout + orderBy( + ...columns: + | [(deleteTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteEffectDeleteWithout { + if (typeof columns[0] === "function") { + const orderBy = columns[0]( + new Proxy( + getTableColumnsRuntime(this.config.table), + new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" }), + ) as any, + ) + + this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy] + return this as any + } + + this.config.orderBy = columns as (SQLiteColumn | SQL | SQL.Aliased)[] + return this as any + } + + limit(limit: number | Placeholder): SQLiteEffectDeleteWithout { + this.config.limit = limit + return this as any + } + + returning(): SQLiteEffectDeleteReturningAll + returning( + fields: TSelectedFields, + ): SQLiteEffectDeleteReturning + returning( + fields: SelectedFieldsFlat = getTableColumnsRuntime(this.table), + ): SQLiteEffectDeleteReturning | SQLiteEffectDeleteReturningAll { + this.config.returning = orderSelectedFields(fields) + return this as any + } + + /** @internal */ + getSQL(): SQL { + return this.effectDialect.buildDeleteQuery(this.config) + } + + toSQL(): Query { + return this.effectDialect.sqlToQuery(this.getSQL()) + } + + /** @internal */ + _prepare(isOneTimeQuery = true): SQLiteEffectDeletePrepare { + return this.effectSession[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"]( + this.effectDialect.sqlToQuery(this.getSQL()), + this.config.returning, + this.config.returning ? "all" : "run", + undefined, + { + type: "delete", + tables: extractUsedTable(this.config.table), + }, + ) as SQLiteEffectDeletePrepare + } + + prepare(): SQLiteEffectDeletePrepare { + return this._prepare(false) + } + + run: ReturnType["run"] = (placeholderValues) => { + return this._prepare().run(placeholderValues) + } + + all: ReturnType["all"] = (placeholderValues) => { + return this._prepare().all(placeholderValues) + } + + get: ReturnType["get"] = (placeholderValues) => { + return this._prepare().get(placeholderValues) + } + + values: ReturnType["values"] = (placeholderValues) => { + return this._prepare().values(placeholderValues) + } + + execute: ReturnType["execute"] = (placeholderValues) => { + return this._prepare().execute(placeholderValues) + } + + $dynamic(): SQLiteEffectDeleteDynamic { + return this as any + } +} + +applyEffectWrapper(SQLiteEffectDeleteBase) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/index.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/index.ts new file mode 100644 index 0000000000..ab7aeb1ab6 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/index.ts @@ -0,0 +1,10 @@ +/* oxlint-disable */ +export * from "./count" +export * from "./db" +export * from "./delete" +export * from "./insert" +export * from "./query" +export * from "./raw" +export * from "./select" +export * from "./session" +export * from "./update" diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/insert.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/insert.ts new file mode 100644 index 0000000000..f85dc24475 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/insert.ts @@ -0,0 +1,349 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind, is } from "drizzle-orm/entity" +import type { SelectResultFields } from "drizzle-orm/query-builders/select.types" +import type { RunnableQuery } from "drizzle-orm/runnable-query" +import type { Query, SQLWrapper } from "drizzle-orm/sql/sql" +import { Param, SQL, sql } from "drizzle-orm/sql/sql" +import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect" +import type { IndexColumn } from "drizzle-orm/sqlite-core/indexes" +import type { + SQLiteInsertConfig, + SQLiteInsertSelectQueryBuilder, + SQLiteInsertValue, +} from "drizzle-orm/sqlite-core/query-builders/insert" +import type { SelectedFieldsFlat } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { PreparedQueryConfig } from "drizzle-orm/sqlite-core/session" +import { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import { extractUsedTable } from "drizzle-orm/sqlite-core/utils" +import type { Subquery } from "drizzle-orm/subquery" +import { type DrizzleTypeError, haveSameKeys } from "drizzle-orm/utils" +import type { SQLiteColumn } from "drizzle-orm/sqlite-core/columns/common" +import { QueryBuilder } from "drizzle-orm/sqlite-core/query-builders/query-builder" +import type { SQLiteUpdateSetSource } from "drizzle-orm/sqlite-core/query-builders/update" +import { getTableColumnsRuntime, mapUpdateSet, orderSelectedFields } from "../../internal/drizzle-utils" +import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session" + +export type SQLiteEffectInsertWithout< + T extends AnySQLiteEffectInsert, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true + ? T + : Omit< + SQLiteEffectInsertBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["returning"], + TDynamic, + T["_"]["excludedMethods"] | K, + T["_"]["effectHKT"] + >, + T["_"]["excludedMethods"] | K + > + +export type SQLiteEffectInsertReturning< + T extends AnySQLiteEffectInsert, + TDynamic extends boolean, + TSelectedFields extends SelectedFieldsFlat, +> = SQLiteEffectInsertWithout< + SQLiteEffectInsertBase< + T["_"]["table"], + T["_"]["runResult"], + SelectResultFields, + TDynamic, + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectInsertReturningAll< + T extends AnySQLiteEffectInsert, + TDynamic extends boolean, +> = SQLiteEffectInsertWithout< + SQLiteEffectInsertBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["table"]["$inferSelect"], + TDynamic, + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectInsertDynamic = SQLiteEffectInsert< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["returning"], + T["_"]["effectHKT"] +> + +export type SQLiteEffectInsertOnConflictDoUpdateConfig = { + target: IndexColumn | IndexColumn[] + /** @deprecated - use either `targetWhere` or `setWhere` */ + where?: SQL + targetWhere?: SQL + setWhere?: SQL + set: SQLiteUpdateSetSource +} + +export type SQLiteEffectInsertExecute = T["_"]["returning"] extends undefined + ? T["_"]["runResult"] + : T["_"]["returning"][] + +export type SQLiteEffectInsertPrepare< + T extends AnySQLiteEffectInsert, + TEffectHKT extends QueryEffectHKTBase = T["_"]["effectHKT"], +> = SQLiteEffectPreparedQuery< + PreparedQueryConfig & { + run: T["_"]["runResult"] + all: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".all() cannot be used without .returning()"> + : T["_"]["returning"][] + get: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".get() cannot be used without .returning()"> + : T["_"]["returning"] + values: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".values() cannot be used without .returning()"> + : any[][] + execute: SQLiteEffectInsertExecute + }, + TEffectHKT +> + +export type SQLiteEffectInsert< + TTable extends SQLiteTable = SQLiteTable, + TRunResult = unknown, + TReturning = any, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> = SQLiteEffectInsertBase + +export type AnySQLiteEffectInsert = SQLiteEffectInsertBase + +export class SQLiteEffectInsertBuilder< + TTable extends SQLiteTable, + TRunResult, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> { + static readonly [entityKind]: string = "SQLiteEffectInsertBuilder" + + constructor( + protected table: TTable, + protected session: SQLiteEffectSession, + protected dialect: SQLiteDialect, + private withList?: Subquery[], + ) {} + + values( + value: SQLiteInsertValue, + ): SQLiteEffectInsertBase + values( + values: SQLiteInsertValue[], + ): SQLiteEffectInsertBase + values( + values: SQLiteInsertValue | SQLiteInsertValue[], + ): SQLiteEffectInsertBase { + values = Array.isArray(values) ? values : [values] + if (values.length === 0) { + throw new Error("values() must be called with at least one value") + } + const mappedValues = values.map((entry) => { + const result: Record = {} + const cols = getTableColumnsRuntime(this.table) + for (const colKey of Object.keys(entry)) { + const colValue = entry[colKey as keyof typeof entry] + result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]) + } + return result + }) + + return new SQLiteEffectInsertBase(this.table, mappedValues, this.session, this.dialect, this.withList) + } + + select( + selectQuery: (qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder, + ): SQLiteEffectInsertBase + select( + selectQuery: (qb: QueryBuilder) => SQL, + ): SQLiteEffectInsertBase + select(selectQuery: SQL): SQLiteEffectInsertBase + select( + selectQuery: SQLiteInsertSelectQueryBuilder, + ): SQLiteEffectInsertBase + select( + selectQuery: + | SQL + | SQLiteInsertSelectQueryBuilder + | ((qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder | SQL), + ): SQLiteEffectInsertBase { + const select = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery + + if (!is(select, SQL) && !haveSameKeys(getTableColumnsRuntime(this.table), select._.selectedFields)) { + throw new Error( + "Insert select error: selected fields are not the same or are in a different order compared to the table definition", + ) + } + + return new SQLiteEffectInsertBase(this.table, select, this.session, this.dialect, this.withList, true) + } +} + +export interface SQLiteEffectInsertBase< + TTable extends SQLiteTable, + TRunResult, + TReturning = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> extends SQLWrapper, + RunnableQuery, + Effect.Effect< + TReturning extends undefined ? TRunResult : TReturning[], + TEffectHKT["error"], + TEffectHKT["context"] + > { + readonly _: { + readonly dialect: "sqlite" + readonly table: TTable + readonly resultType: "async" + readonly runResult: TRunResult + readonly returning: TReturning + readonly dynamic: TDynamic + readonly excludedMethods: _TExcludedMethods + readonly result: TReturning extends undefined ? TRunResult : TReturning[] + readonly effectHKT: TEffectHKT + } +} + +export class SQLiteEffectInsertBase< + TTable extends SQLiteTable, + TRunResult, + TReturning = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + > + implements RunnableQuery, SQLWrapper +{ + static readonly [entityKind]: string = "SQLiteEffectInsert" + + /** @internal */ + config: SQLiteInsertConfig + + constructor( + private table: TTable, + values: SQLiteInsertConfig["values"], + private effectSession: SQLiteEffectSession, + private effectDialect: SQLiteDialect, + withList?: Subquery[], + select?: boolean, + ) { + this.config = { table, values: values as any, withList, select } + } + + returning(): SQLiteEffectInsertReturningAll + returning( + fields: TSelectedFields, + ): SQLiteEffectInsertReturning + returning( + fields: SelectedFieldsFlat = getTableColumnsRuntime(this.config.table), + ): SQLiteEffectInsertWithout { + this.config.returning = orderSelectedFields(fields) + return this as any + } + + onConflictDoNothing(config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}): this { + if (!this.config.onConflict) this.config.onConflict = [] + + if (config.target === undefined) { + this.config.onConflict.push(sql` on conflict do nothing`) + return this + } + + const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}` + const whereSql = config.where ? sql` where ${config.where}` : sql`` + this.config.onConflict.push(sql` on conflict ${targetSql} do nothing${whereSql}`) + return this + } + + onConflictDoUpdate(config: SQLiteEffectInsertOnConflictDoUpdateConfig): this { + if (config.where && (config.targetWhere || config.setWhere)) { + throw new Error( + 'You cannot use both "where" and "targetWhere"/"setWhere" at the same time - "where" is deprecated, use "targetWhere" or "setWhere" instead.', + ) + } + + if (!this.config.onConflict) this.config.onConflict = [] + + const whereSql = config.where ? sql` where ${config.where}` : undefined + const targetWhereSql = config.targetWhere ? sql` where ${config.targetWhere}` : undefined + const setWhereSql = config.setWhere ? sql` where ${config.setWhere}` : undefined + const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}` + const setSql = this.effectDialect.buildUpdateSet( + this.config.table, + mapUpdateSet(this.config.table, config.set as SQLiteUpdateSetSource), + ) + this.config.onConflict.push( + sql` on conflict ${targetSql}${targetWhereSql} do update set ${setSql}${whereSql}${setWhereSql}`, + ) + return this + } + + /** @internal */ + getSQL(): SQL { + return this.effectDialect.buildInsertQuery(this.config) + } + + toSQL(): Query { + return this.effectDialect.sqlToQuery(this.getSQL()) + } + + /** @internal */ + _prepare(isOneTimeQuery = true): SQLiteEffectInsertPrepare { + return this.effectSession[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"]( + this.effectDialect.sqlToQuery(this.getSQL()), + this.config.returning, + this.config.returning ? "all" : "run", + undefined, + { + type: "insert", + tables: extractUsedTable(this.config.table), + }, + ) as SQLiteEffectInsertPrepare + } + + prepare(): SQLiteEffectInsertPrepare { + return this._prepare(false) + } + + run: ReturnType["run"] = (placeholderValues) => { + return this._prepare().run(placeholderValues) + } + + all: ReturnType["all"] = (placeholderValues) => { + return this._prepare().all(placeholderValues) + } + + get: ReturnType["get"] = (placeholderValues) => { + return this._prepare().get(placeholderValues) + } + + values: ReturnType["values"] = (placeholderValues) => { + return this._prepare().values(placeholderValues) + } + + execute: ReturnType["execute"] = (placeholderValues) => { + return this._prepare().execute(placeholderValues) + } + + $dynamic(): SQLiteEffectInsertDynamic { + return this as any + } +} + +applyEffectWrapper(SQLiteEffectInsertBase) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/query.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/query.ts new file mode 100644 index 0000000000..4676039e55 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/query.ts @@ -0,0 +1,198 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import { + type BuildQueryResult, + type BuildRelationalQueryResult, + type DBQueryConfig, + makeDefaultRqbMapper, + type TableRelationalConfig, + type TablesRelationalConfig, +} from "drizzle-orm/relations" +import type { RunnableQuery } from "drizzle-orm/runnable-query" +import { type Query, type SQL, sql, type SQLWrapper } from "drizzle-orm/sql/sql" +import type { KnownKeysOnly } from "drizzle-orm/utils" +import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect" +import type { PreparedQueryConfig } from "drizzle-orm/sqlite-core/session" +import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session" + +export class SQLiteEffectRelationalQueryBuilder< + TSchema extends TablesRelationalConfig, + TFields extends TableRelationalConfig, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> { + static readonly [entityKind]: string = "SQLiteEffectRelationalQueryBuilderV2" + + constructor( + private schema: TSchema, + private table: SQLiteTable, + private tableConfig: TableRelationalConfig, + private dialect: SQLiteDialect, + private session: SQLiteEffectSession, + private rowMode?: boolean, + private forbidJsonb?: boolean, + ) {} + + findMany>( + config?: KnownKeysOnly>, + ): SQLiteEffectRelationalQuery[], TEffectHKT> { + return new SQLiteEffectRelationalQuery( + this.schema, + this.table, + this.tableConfig, + this.dialect, + this.session, + (config as DBQueryConfig<"many"> | undefined) ?? true, + "many", + this.rowMode, + this.forbidJsonb, + ) + } + + findFirst>( + config?: KnownKeysOnly>, + ): SQLiteEffectRelationalQuery | undefined, TEffectHKT> { + return new SQLiteEffectRelationalQuery( + this.schema, + this.table, + this.tableConfig, + this.dialect, + this.session, + (config as DBQueryConfig<"one"> | undefined) ?? true, + "first", + this.rowMode, + this.forbidJsonb, + ) + } +} + +export interface SQLiteEffectRelationalQuery + extends Effect.Effect, + RunnableQuery, + SQLWrapper {} + +export class SQLiteEffectRelationalQuery + implements RunnableQuery, SQLWrapper +{ + static readonly [entityKind]: string = "SQLiteEffectRelationalQueryV2" + + declare readonly _: { + readonly dialect: "sqlite" + readonly type: "async" + readonly result: TResult + } + + /** @internal */ + mode: "many" | "first" + /** @internal */ + table: SQLiteTable + + constructor( + private schema: TablesRelationalConfig, + table: SQLiteTable, + private tableConfig: TableRelationalConfig, + private dialect: SQLiteDialect, + private session: SQLiteEffectSession, + private config: DBQueryConfig<"many" | "one"> | true, + mode: "many" | "first", + private rowMode?: boolean, + private forbidJsonb?: boolean, + ) { + this.mode = mode + this.table = table + } + + /** @internal */ + getSQL(): SQL { + return this._getQuery().sql + } + + /** @internal */ + _prepare( + isOneTimeQuery = true, + ): SQLiteEffectPreparedQuery< + PreparedQueryConfig & { all: TResult; get: TResult; execute: TResult }, + TEffectHKT, + true + > { + const { query, builtQuery } = this._toSQL() + const mapperConfig = { + isFirst: this.mode === "first", + parseJson: !this.rowMode, + parseJsonIfString: false, + rootJsonMappers: true, + selection: query.selection, + } + + return this.session[isOneTimeQuery ? "prepareOneTimeRelationalQuery" : "prepareRelationalQuery"]( + builtQuery, + undefined, + this.mode === "first" ? "get" : "all", + makeDefaultRqbMapper(mapperConfig), + mapperConfig, + ) as SQLiteEffectPreparedQuery< + PreparedQueryConfig & { all: TResult; get: TResult; execute: TResult }, + TEffectHKT, + true + > + } + + prepare(): SQLiteEffectPreparedQuery< + PreparedQueryConfig & { all: TResult; get: TResult; execute: TResult }, + TEffectHKT, + true + > { + return this._prepare(false) + } + + private _getQuery() { + const jsonb = this.forbidJsonb ? sql`json` : sql`jsonb` + + const query = this.dialect.buildRelationalQuery({ + schema: this.schema, + table: this.table, + tableConfig: this.tableConfig, + queryConfig: this.config, + mode: this.mode, + isNested: this.rowMode, + jsonb, + }) + + if (this.rowMode) { + const jsonColumns = sql.join( + query.selection.map((s) => { + return sql`${sql.raw(this.dialect.escapeString(s.key))}, ${ + s.selection ? sql`${jsonb}(${sql.identifier(s.key)})` : sql.identifier(s.key) + }` + }), + sql`, `, + ) + + query.sql = sql`select json_object(${jsonColumns}) as ${sql.identifier("r")} from (${query.sql}) as ${sql.identifier( + "t", + )}` + } + + return query + } + + private _toSQL(): { query: BuildRelationalQueryResult; builtQuery: Query } { + const query = this._getQuery() + + const builtQuery = this.dialect.sqlToQuery(query.sql) + + return { query, builtQuery } + } + + toSQL(): Query { + return this._toSQL().builtQuery + } + + execute(placeholderValues?: Record) { + return this.mode === "first" ? this._prepare().get(placeholderValues) : this._prepare().all(placeholderValues) + } +} + +applyEffectWrapper(SQLiteEffectRelationalQuery) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/raw.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/raw.ts new file mode 100644 index 0000000000..26e3a63d83 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/raw.ts @@ -0,0 +1,49 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind } from "drizzle-orm/entity" +import type { RunnableQuery } from "drizzle-orm/runnable-query" +import type { PreparedQuery } from "drizzle-orm/session" +import type { Query, SQL, SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" + +type SQLiteEffectRawAction = "all" | "get" | "values" | "run" + +export interface SQLiteEffectRaw + extends Effect.Effect, + RunnableQuery, + SQLWrapper {} + +export class SQLiteEffectRaw + implements RunnableQuery, SQLWrapper, PreparedQuery +{ + static readonly [entityKind]: string = "SQLiteEffectRaw" + + declare readonly _: { + readonly dialect: "sqlite" + readonly result: TResult + } + + constructor( + public execute: () => Effect.Effect, + /** @internal */ + public getSQL: () => SQL, + private action: SQLiteEffectRawAction, + private dialect: SQLiteAsyncDialect, + private mapBatchResult: (result: unknown) => unknown, + ) {} + + getQuery(): Query & { method: SQLiteEffectRawAction } { + return { ...this.dialect.sqlToQuery(this.getSQL()), method: this.action } + } + + mapResult(result: unknown, isFromBatch?: boolean) { + return isFromBatch ? this.mapBatchResult(result) : result + } + + _prepare(): PreparedQuery { + return this + } +} + +applyEffectWrapper(SQLiteEffectRaw) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/select.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/select.ts new file mode 100644 index 0000000000..0cfde54331 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/select.ts @@ -0,0 +1,279 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import type { CacheConfig } from "drizzle-orm/cache/core/types" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind, is } from "drizzle-orm/entity" +import type { + BuildSubquerySelection, + GetSelectTableName, + GetSelectTableSelection, + JoinNullability, + SelectMode, + SelectResult, +} from "drizzle-orm/query-builders/select.types" +import { SQL } from "drizzle-orm/sql/sql" +import type { ColumnsSelection, SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteColumn } from "drizzle-orm/sqlite-core/columns" +import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect" +import { SQLiteSelectQueryBuilderBase } from "drizzle-orm/sqlite-core/query-builders/select" +import type { + CreateSQLiteSelectFromBuilderMode, + SelectedFields, + SQLiteSelectConfig, + SQLiteSelectHKTBase, +} from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import { SQLiteViewBase } from "drizzle-orm/sqlite-core/view-base" +import { Subquery } from "drizzle-orm/subquery" +import { type Assume, getTableColumns } from "drizzle-orm/utils" +import { getViewSelectedFieldsRuntime, orderSelectedFields } from "../../internal/drizzle-utils" +import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session" + +export type SQLiteEffectSelectPrepare< + T extends AnySQLiteEffectSelect, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> = SQLiteEffectPreparedQuery< + { + type: "async" + run: T["_"]["runResult"] + all: T["_"]["result"] + get: T["_"]["result"][number] | undefined + values: any[][] + execute: T["_"]["result"] + }, + TEffectHKT +> + +export class SQLiteEffectSelectBuilder< + TSelection extends SelectedFields | undefined, + TRunResult, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + TBuilderMode extends "db" | "qb" = "db", +> { + static readonly [entityKind]: string = "SQLiteEffectSelectBuilder" + + private fields: TSelection + private session: SQLiteEffectSession | undefined + private dialect: SQLiteDialect + private withList: Subquery[] | undefined + private distinct: boolean | undefined + + constructor(config: { + fields: TSelection + session: SQLiteEffectSession | undefined + dialect: SQLiteDialect + withList?: Subquery[] + distinct?: boolean + }) { + this.fields = config.fields + this.session = config.session + this.dialect = config.dialect + this.withList = config.withList + this.distinct = config.distinct + } + + from( + source: TFrom, + ): TBuilderMode extends "db" + ? SQLiteEffectSelectBase< + GetSelectTableName, + TRunResult, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? "single" : "partial", + GetSelectTableName extends string ? Record, "not-null"> : {}, + false, + never, + SelectResult< + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? "single" : "partial", + GetSelectTableName extends string ? Record, "not-null"> : {} + >[], + BuildSubquerySelection< + TSelection extends undefined ? GetSelectTableSelection : TSelection, + GetSelectTableName extends string ? Record, "not-null"> : {} + >, + TEffectHKT + > + : CreateSQLiteSelectFromBuilderMode< + TBuilderMode, + GetSelectTableName, + "async", + TRunResult, + TSelection extends undefined ? GetSelectTableSelection : TSelection, + TSelection extends undefined ? "single" : "partial" + > { + const isPartialSelect = !!this.fields + + let fields: SelectedFields + if (this.fields) { + fields = this.fields + } else if (is(source, Subquery)) { + fields = Object.fromEntries( + Object.keys(source._.selectedFields).map((key) => [ + key, + source[key as unknown as keyof typeof source] as unknown as SelectedFields[string], + ]), + ) + } else if (is(source, SQLiteViewBase)) { + fields = getViewSelectedFieldsRuntime(source).selectedFields as SelectedFields + } else if (is(source, SQL)) { + fields = {} + } else { + fields = getTableColumns(source) + } + + return new SQLiteEffectSelectBase({ + table: source, + fields, + isPartialSelect, + session: this.session as any, + dialect: this.dialect, + withList: this.withList, + distinct: this.distinct, + }) as any + } +} + +export interface SQLiteEffectSelectHKT + extends SQLiteSelectHKTBase { + _type: SQLiteEffectSelectBase< + this["tableName"], + this["runResult"], + Assume, + this["selectMode"], + Assume>, + this["dynamic"], + this["excludedMethods"], + Assume, + Assume, + TEffectHKT + > +} + +export interface SQLiteEffectSelectBase< + TTableName extends string | undefined, + TRunResult, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode = "single", + TNullabilityMap extends Record = TTableName extends string + ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> extends SQLiteSelectQueryBuilderBase< + SQLiteEffectSelectHKT, + TTableName, + "async", + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + >, + Effect.Effect {} + +export class SQLiteEffectSelectBase< + TTableName extends string | undefined, + TRunResult, + TSelection extends ColumnsSelection, + TSelectMode extends SelectMode = "single", + TNullabilityMap extends Record = TTableName extends string + ? Record + : {}, + TDynamic extends boolean = false, + TExcludedMethods extends string = never, + TResult extends any[] = SelectResult[], + TSelectedFields extends ColumnsSelection = BuildSubquerySelection, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + > + extends SQLiteSelectQueryBuilderBase< + SQLiteEffectSelectHKT, + TTableName, + "async", + TRunResult, + TSelection, + TSelectMode, + TNullabilityMap, + TDynamic, + TExcludedMethods, + TResult, + TSelectedFields + > + implements SQLWrapper +{ + static override readonly [entityKind]: string = "SQLiteEffectSelect" + + private get effectConfig() { + return (this as unknown as { config: SQLiteSelectConfig }).config + } + + /** @internal */ + getSQL(): SQL { + return this.dialect.buildSelectQuery(this.effectConfig) + } + + /** @internal */ + _prepare(isOneTimeQuery = true): SQLiteEffectSelectPrepare { + if (!this.session) { + throw new Error("Cannot execute a query on a query builder. Please use a database instance instead.") + } + const session = this.session as unknown as SQLiteEffectSession + const query = session[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"]( + this.dialect.sqlToQuery(this.getSQL()), + orderSelectedFields(this.effectConfig.fields), + "all", + undefined, + { + type: "select", + tables: [...this.usedTables], + }, + this.cacheConfig, + ) + query.joinsNotNullableMap = this.joinsNotNullableMap + return query as ReturnType + } + + $withCache(config?: { config?: CacheConfig; tag?: string; autoInvalidate?: boolean } | false) { + this.cacheConfig = + config === undefined + ? { config: {}, enabled: true, autoInvalidate: true } + : config === false + ? { enabled: false } + : { enabled: true, autoInvalidate: true, ...config } + return this + } + + prepare(): SQLiteEffectSelectPrepare { + return this._prepare(false) + } + + run: ReturnType["run"] = (placeholderValues) => { + return this._prepare().run(placeholderValues) + } + + all: ReturnType["all"] = (placeholderValues) => { + return this._prepare().all(placeholderValues) + } + + get: ReturnType["get"] = (placeholderValues) => { + return this._prepare().get(placeholderValues) + } + + values: ReturnType["values"] = (placeholderValues) => { + return this._prepare().values(placeholderValues) + } + + execute: ReturnType["execute"] = (placeholderValues) => { + return this._prepare().execute(placeholderValues) + } +} + +applyEffectWrapper(SQLiteEffectSelectBase) + +export type AnySQLiteEffectSelect = SQLiteEffectSelectBase diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/session.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/session.ts new file mode 100644 index 0000000000..15a56f2ca7 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/session.ts @@ -0,0 +1,490 @@ +/* oxlint-disable */ +import * as Cause from "effect/Cause" +import * as Effect from "effect/Effect" +import type { SqlError } from "effect/unstable/sql/SqlError" +import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" +import { NoopCache, strategyFor } from "drizzle-orm/cache/core/cache" +import type { WithCacheConfig } from "drizzle-orm/cache/core/types" +import { MigratorInitError } from "drizzle-orm/effect-core/errors" +import { EffectDrizzleQueryError, EffectTransactionRollbackError } from "drizzle-orm/effect-core/errors" +import type { EffectLoggerShape } from "drizzle-orm/effect-core/logger" +import type { QueryEffectHKTBase, QueryEffectKind } from "drizzle-orm/effect-core/query-effect" +import { entityKind, is } from "drizzle-orm/entity" +import type { MigrationConfig, MigrationMeta } from "drizzle-orm/migrator" +import { getMigrationsToRun } from "drizzle-orm/migrator.utils" +import type { + AnyRelations, + EmptyRelations, + RelationalQueryMapperConfig, + RelationalRowsMapper, +} from "drizzle-orm/relations" +import { makeJitRqbMapper } from "drizzle-orm/relations" +import type { PreparedQuery } from "drizzle-orm/session" +import { fillPlaceholders, type Query, type SQL, sql } from "drizzle-orm/sql/sql" +import type { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" +import type { SelectedFieldsOrdered } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { PreparedQueryConfig, SQLiteExecuteMethod, SQLiteTransactionConfig } from "drizzle-orm/sqlite-core/session" +import { upgradeIfNeeded } from "../../up-migrations/effect-sqlite" +import { assertUnreachable, makeJitQueryMapper, type RowsMapper } from "drizzle-orm/utils" +import { mapResultRow } from "../../internal/drizzle-utils" +import { SQLiteEffectDatabase } from "./db" + +type MigrationConfigWithInit = MigrationConfig & { init?: boolean } + +type SQLiteEffectExecuteMethod = SQLiteExecuteMethod | "values" + +export class SQLiteEffectPreparedQuery< + T extends PreparedQueryConfig, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + TIsRqbV2 extends boolean = false, +> implements PreparedQuery +{ + static readonly [entityKind]: string = "SQLiteEffectPreparedQuery" + + /** @internal */ + joinsNotNullableMap?: Record + private jitMapper?: RowsMapper | RelationalRowsMapper + private cacheConfig: WithCacheConfig | undefined + private effectExecuteMethod: SQLiteExecuteMethod + + constructor( + private executor: ( + params: unknown[], + executeMethod: SQLiteEffectExecuteMethod, + ) => Effect.Effect, + protected query: Query, + private logger: EffectLoggerShape, + private cache: EffectCacheShape, + private queryMetadata: + | { + type: "select" | "update" | "delete" | "insert" + tables: string[] + } + | undefined, + cacheConfig: WithCacheConfig | undefined, + private fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + private useJitMappers: boolean | undefined, + private customResultMapper?: ( + rows: TIsRqbV2 extends true ? Record[] : unknown[][], + mapColumnValue?: (value: unknown) => unknown, + ) => unknown, + private isRqbV2Query?: TIsRqbV2, + private rqbConfig?: RelationalQueryMapperConfig, + private isInTransaction: Effect.Effect = Effect.succeed(false), + ) { + this.effectExecuteMethod = executeMethod + this.cacheConfig = + cache.strategy() === "all" && cacheConfig === undefined ? { enabled: true, autoInvalidate: true } : cacheConfig + if (!this.cacheConfig?.enabled) { + this.cacheConfig = undefined + } + } + + run(placeholderValues?: Record): QueryEffectKind + run(placeholderValues?: Record): any { + return this.executeWithCache(placeholderValues, "run") + } + + all(placeholderValues?: Record): QueryEffectKind + all(placeholderValues?: Record): any { + if (this.isRqbV2Query) return this.allRqbV2(placeholderValues) + + if (!this.fields && !this.customResultMapper) { + return this.executeWithCache(placeholderValues, "all") + } + + return this.executeWithCache( + placeholderValues, + "values", + (rows) => this.mapAllResult(rows) as T["all"], + ) + } + + get(placeholderValues?: Record): QueryEffectKind + get(placeholderValues?: Record): any { + if (this.isRqbV2Query) return this.getRqbV2(placeholderValues) + + if (!this.fields && !this.customResultMapper) { + return this.executeWithCache(placeholderValues, "get") + } + + return this.executeWithCache( + placeholderValues, + "values", + (rows) => this.mapGetResult(rows) as T["get"], + ) + } + + values(placeholderValues?: Record): QueryEffectKind + values(placeholderValues?: Record): any { + return this.executeWithCache(placeholderValues, "values") + } + + execute(placeholderValues?: Record): QueryEffectKind + execute(placeholderValues?: Record): any { + return this[this.effectExecuteMethod](placeholderValues) as QueryEffectKind + } + + mapRunResult(result: unknown, _isFromBatch?: boolean): unknown { + return result + } + + mapAllResult(rows: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + rows = Array.isArray(rows) ? rows : [] + } + + if (!this.fields && !this.customResultMapper) { + return rows + } + + if (this.isRqbV2Query) { + return this.useJitMappers + ? (this.jitMapper = + (this.jitMapper as RelationalRowsMapper) ?? makeJitRqbMapper(this.rqbConfig!))( + rows as Record[], + ) + : (this.customResultMapper as (rows: Record[]) => unknown)(rows as Record[]) + } + + if (this.customResultMapper) { + return (this.customResultMapper as (rows: unknown[][]) => unknown)(rows as unknown[][]) as T["all"] + } + + return this.useJitMappers + ? (this.jitMapper = + (this.jitMapper as RowsMapper) ?? + makeJitQueryMapper(this.fields!, this.joinsNotNullableMap))(rows as unknown[][]) + : (rows as unknown[][]).map((row) => mapResultRow(this.fields!, row, this.joinsNotNullableMap)) + } + + mapGetResult(rows: unknown, isFromBatch?: boolean): unknown { + if (isFromBatch) { + rows = Array.isArray(rows) ? rows : [] + } + + if (!this.fields && !this.customResultMapper) { + return Array.isArray(rows) ? rows[0] : rows + } + + const row = Array.isArray(rows) ? rows[0] : rows + if (!row) return undefined + + if (this.isRqbV2Query) { + return this.useJitMappers + ? (this.jitMapper = + (this.jitMapper as RelationalRowsMapper) ?? makeJitRqbMapper(this.rqbConfig!))([ + row as Record, + ]) + : (this.customResultMapper as (rows: Record[]) => unknown)([row as Record]) + } + + if (this.customResultMapper) { + return (this.customResultMapper as (rows: unknown[][]) => unknown)([row as unknown[]]) as T["get"] + } + + return this.useJitMappers + ? (this.jitMapper = + (this.jitMapper as RowsMapper) ?? + makeJitQueryMapper(this.fields!, this.joinsNotNullableMap))([row as unknown[]])[0] + : mapResultRow(this.fields!, row as unknown[], this.joinsNotNullableMap) + } + + private allRqbV2(placeholderValues?: Record) { + return this.executeWithCache( + placeholderValues, + "all", + (rows) => this.mapAllResult(rows) as T["all"], + ) + } + + private getRqbV2(placeholderValues?: Record) { + return this.executeWithCache(placeholderValues, "get", (row) => + row === undefined ? undefined : (this.mapGetResult(row) as T["get"]), + ) + } + + private executeWithCache( + placeholderValues: Record | undefined, + executeMethod: SQLiteEffectExecuteMethod, + mapResult?: (result: A) => B, + ) { + return Effect.gen({ self: this }, function* () { + const params = fillPlaceholders(this.query.params, placeholderValues ?? {}) + + yield* this.logger.logQuery(this.query.sql, params) + + return yield* this.queryWithCache( + this.query.sql, + params, + Effect.suspend(() => this.executor(params, executeMethod) as Effect.Effect), + mapResult, + ) + }) + } + + private mapCachedResult(result: A, mapResult: ((result: A) => B) | undefined) { + if (!mapResult) return Effect.succeed(result as unknown as B) + return Effect.try({ + try: () => mapResult(result), + catch: (cause) => cause, + }) + } + + private queryWithCache( + queryString: string, + params: unknown[], + query: Effect.Effect, + mapResult?: (result: A) => B, + ) { + return Effect.gen({ self: this }, function* () { + if (this.queryMetadata?.type === "select" && this.cacheConfig?.enabled && (yield* this.isInTransaction)) { + return yield* this.mapCachedResult(yield* query, mapResult) + } + + const cacheStrat: Awaited> = !is(this.cache.cache, NoopCache) + ? yield* Effect.tryPromise(() => strategyFor(queryString, params, this.queryMetadata, this.cacheConfig)) + : { type: "skip" as const } + + if (cacheStrat.type === "skip") { + return yield* this.mapCachedResult(yield* query, mapResult) + } + + if (cacheStrat.type === "invalidate") { + const result = yield* query + yield* this.cache.onMutate({ tables: cacheStrat.tables }) + return yield* this.mapCachedResult(result, mapResult) + } + + if (cacheStrat.type === "try") { + if (yield* this.isInTransaction) { + return yield* this.mapCachedResult(yield* query, mapResult) + } + + const { tables, key, isTag, autoInvalidate, config } = cacheStrat + const fromCache: any[] | undefined = yield* this.cache.get(key, tables, isTag, autoInvalidate) + + if (typeof fromCache !== "undefined") { + return yield* this.mapCachedResult(fromCache as unknown as A, mapResult) + } + + const result = yield* query + + yield* this.cache.put(key, result, autoInvalidate ? tables : [], isTag, config) + + return yield* this.mapCachedResult(result, mapResult) + } + + assertUnreachable(cacheStrat) + }).pipe( + Effect.catch((e) => { + return Effect.fail(new EffectDrizzleQueryError({ query: queryString, params, cause: Cause.fail(e) })) + }), + ) + } + + getQuery(): Query { + return this.query + } + + mapResult(response: unknown, isFromBatch?: boolean) { + switch (this.effectExecuteMethod) { + case "run": { + return this.mapRunResult(response, isFromBatch) + } + case "all": { + return this.mapAllResult(response, isFromBatch) + } + case "get": { + return this.mapGetResult(response, isFromBatch) + } + } + } +} + +export abstract class SQLiteEffectSession< + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + TRunResult = unknown, + TRelations extends AnyRelations = EmptyRelations, +> { + static readonly [entityKind]: string = "SQLiteEffectSession" + + constructor(readonly dialect: SQLiteAsyncDialect) {} + + abstract prepareQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, + queryMetadata?: { + type: "select" | "update" | "delete" | "insert" + tables: string[] + }, + cacheConfig?: WithCacheConfig, + ): SQLiteEffectPreparedQuery + + prepareOneTimeQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper?: (rows: unknown[][], mapColumnValue?: (value: unknown) => unknown) => unknown, + queryMetadata?: { + type: "select" | "update" | "delete" | "insert" + tables: string[] + }, + cacheConfig?: WithCacheConfig, + ): SQLiteEffectPreparedQuery { + return this.prepareQuery(query, fields, executeMethod, customResultMapper, queryMetadata, cacheConfig) + } + + abstract prepareRelationalQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper: (rows: Record[], mapColumnValue?: (value: unknown) => unknown) => unknown, + config: RelationalQueryMapperConfig, + ): SQLiteEffectPreparedQuery + + prepareOneTimeRelationalQuery( + query: Query, + fields: SelectedFieldsOrdered | undefined, + executeMethod: SQLiteExecuteMethod, + customResultMapper: (rows: Record[], mapColumnValue?: (value: unknown) => unknown) => unknown, + config: RelationalQueryMapperConfig, + ): SQLiteEffectPreparedQuery { + return this.prepareRelationalQuery(query, fields, executeMethod, customResultMapper, config) + } + + run(query: SQL): QueryEffectKind + run(query: SQL): any { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + "run", + ).run() + } + + all(query: SQL): QueryEffectKind + all(query: SQL): any { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + "all", + ).all() + } + + get(query: SQL): QueryEffectKind + get(query: SQL): any { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + "get", + ).get() + } + + values(query: SQL): QueryEffectKind + values(query: SQL): any { + return this.prepareQuery( + this.dialect.sqlToQuery(query), + undefined, + "all", + ).values() + } + + count(query: SQL): QueryEffectKind + count(query: SQL): any { + return this.values<[number]>(query).pipe(Effect.map((result) => result[0]?.[0] ?? 0)) + } + + abstract transaction( + transaction: (tx: SQLiteEffectTransaction) => Effect.Effect, + config?: SQLiteTransactionConfig, + ): Effect.Effect +} + +export abstract class SQLiteEffectTransaction< + TEffectHKT extends QueryEffectHKTBase, + TRunResult, + TRelations extends AnyRelations = EmptyRelations, +> extends SQLiteEffectDatabase { + static override readonly [entityKind]: string = "SQLiteEffectTransaction" + + constructor( + dialect: SQLiteAsyncDialect, + session: SQLiteEffectSession, + protected relations: TRelations, + ) { + super(dialect, session, relations) + } + + rollback() { + return new EffectTransactionRollbackError() + } +} + +export const migrate = Effect.fn("migrate")(function* ( + migrations: MigrationMeta[], + session: SQLiteEffectSession, + config: string | MigrationConfigWithInit, +) { + const migrationsTable = + typeof config === "string" ? "__drizzle_migrations" : (config.migrationsTable ?? "__drizzle_migrations") + + const { newDb } = yield* upgradeIfNeeded(migrationsTable, session, migrations) + + if (newDb) { + yield* session.run(sql` + CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsTable)} ( + id INTEGER PRIMARY KEY, + hash text NOT NULL, + created_at numeric, + name text, + applied_at TEXT + ) + `) + } + + const dbMigrations = yield* session.all<{ id: number; hash: string; created_at: string; name: string | null }>( + sql`SELECT id, hash, created_at, name FROM ${sql.identifier(migrationsTable)}`, + ) + + if (typeof config === "object" && config.init) { + if (dbMigrations.length) { + return yield* new MigratorInitError({ exitCode: "databaseMigrations" }) + } + + if (migrations.length > 1) { + return yield* new MigratorInitError({ exitCode: "localMigrations" }) + } + + const [migration] = migrations + if (!migration) return + + yield* session.run( + sql`insert into ${sql.identifier( + migrationsTable, + )} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${new Date().toISOString()})`, + ) + + return + } + + const migrationsToRun = getMigrationsToRun({ localMigrations: migrations, dbMigrations }) + if (migrationsToRun.length === 0) return + + yield* session.transaction((tx) => + Effect.gen(function* () { + for (const migration of migrationsToRun) { + for (const stmt of migration.sql) { + yield* tx.run(sql.raw(stmt)) + } + yield* tx.run( + sql`insert into ${sql.identifier( + migrationsTable, + )} ("hash", "created_at", "name", "applied_at") values(${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${new Date().toISOString()})`, + ) + } + }), + ) +}) diff --git a/packages/effect-drizzle-sqlite/src/sqlite-core/effect/update.ts b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/update.ts new file mode 100644 index 0000000000..369e08e878 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/sqlite-core/effect/update.ts @@ -0,0 +1,402 @@ +/* oxlint-disable */ +import type * as Effect from "effect/Effect" +import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import { entityKind, is } from "drizzle-orm/entity" +import type { SelectResultFields } from "drizzle-orm/query-builders/select.types" +import type { RunnableQuery } from "drizzle-orm/runnable-query" +import { SelectionProxyHandler } from "drizzle-orm/selection-proxy" +import type { Placeholder, Query, SQL, SQLWrapper } from "drizzle-orm/sql/sql" +import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect" +import type { SelectedFields, SQLiteSelectJoinConfig } from "drizzle-orm/sqlite-core/query-builders/select.types" +import type { SQLiteUpdateConfig, SQLiteUpdateSetSource } from "drizzle-orm/sqlite-core/query-builders/update" +import type { PreparedQueryConfig } from "drizzle-orm/sqlite-core/session" +import { SQLiteTable } from "drizzle-orm/sqlite-core/table" +import { extractUsedTable } from "drizzle-orm/sqlite-core/utils" +import { SQLiteViewBase } from "drizzle-orm/sqlite-core/view-base" +import { Subquery } from "drizzle-orm/subquery" +import { type DrizzleTypeError, type UpdateSet, type ValueOrArray } from "drizzle-orm/utils" +import type { SQLiteColumn } from "drizzle-orm/sqlite-core/columns/common" +import { + getTableColumnsRuntime, + getTableLikeName, + getViewSelectedFieldsRuntime, + mapUpdateSet, + orderSelectedFields, +} from "../../internal/drizzle-utils" +import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session" + +export type SQLiteEffectUpdateWithout< + T extends AnySQLiteEffectUpdate, + TDynamic extends boolean, + K extends keyof T & string, +> = TDynamic extends true + ? T + : Omit< + SQLiteEffectUpdateBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["from"], + T["_"]["returning"], + TDynamic, + T["_"]["excludedMethods"] | K, + T["_"]["effectHKT"] + >, + T["_"]["excludedMethods"] | K + > + +export type SQLiteEffectUpdateWithJoins< + T extends AnySQLiteEffectUpdate, + TDynamic extends boolean, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL, +> = TDynamic extends true + ? T + : Omit< + SQLiteEffectUpdateBase< + T["_"]["table"], + T["_"]["runResult"], + TFrom, + T["_"]["returning"], + TDynamic, + Exclude, + T["_"]["effectHKT"] + >, + Exclude + > + +export type SQLiteEffectUpdateReturningAll< + T extends AnySQLiteEffectUpdate, + TDynamic extends boolean, +> = SQLiteEffectUpdateWithout< + SQLiteEffectUpdateBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["from"], + T["_"]["table"]["$inferSelect"], + TDynamic, + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectUpdateReturning< + T extends AnySQLiteEffectUpdate, + TDynamic extends boolean, + TSelectedFields extends SelectedFields, +> = SQLiteEffectUpdateWithout< + SQLiteEffectUpdateBase< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["from"], + SelectResultFields, + TDynamic, + T["_"]["excludedMethods"], + T["_"]["effectHKT"] + >, + TDynamic, + "returning" +> + +export type SQLiteEffectUpdateExecute = T["_"]["returning"] extends undefined + ? T["_"]["runResult"] + : T["_"]["returning"][] + +export type SQLiteEffectUpdatePrepare< + T extends AnySQLiteEffectUpdate, + TEffectHKT extends QueryEffectHKTBase = T["_"]["effectHKT"], +> = SQLiteEffectPreparedQuery< + PreparedQueryConfig & { + run: T["_"]["runResult"] + all: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".all() cannot be used without .returning()"> + : T["_"]["returning"][] + get: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".get() cannot be used without .returning()"> + : T["_"]["returning"] + values: T["_"]["returning"] extends undefined + ? DrizzleTypeError<".values() cannot be used without .returning()"> + : any[][] + execute: SQLiteEffectUpdateExecute + }, + TEffectHKT +> + +export type SQLiteEffectUpdateDynamic = SQLiteEffectUpdate< + T["_"]["table"], + T["_"]["runResult"], + T["_"]["from"], + T["_"]["returning"], + T["_"]["effectHKT"] +> + +export type SQLiteEffectUpdate< + TTable extends SQLiteTable = SQLiteTable, + TRunResult = unknown, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, + TReturning extends Record | undefined = Record | undefined, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> = SQLiteEffectUpdateBase + +export type AnySQLiteEffectUpdate = SQLiteEffectUpdateBase + +export type SQLiteEffectUpdateJoinFn = < + TJoinedTable extends SQLiteTable | Subquery | SQLiteViewBase | SQL, +>( + table: TJoinedTable, + on: + | (( + updateTable: T["_"]["table"]["_"]["columns"], + from: T["_"]["from"] extends SQLiteTable + ? T["_"]["from"]["_"]["columns"] + : T["_"]["from"] extends Subquery | SQLiteViewBase + ? T["_"]["from"]["_"]["selectedFields"] + : never, + ) => SQL | undefined) + | SQL + | undefined, +) => T + +export class SQLiteEffectUpdateBuilder< + TTable extends SQLiteTable, + TRunResult, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> { + static readonly [entityKind]: string = "SQLiteEffectUpdateBuilder" + + declare readonly _: { + readonly table: TTable + } + + constructor( + protected table: TTable, + protected session: SQLiteEffectSession, + protected dialect: SQLiteDialect, + private withList?: Subquery[], + ) {} + + set( + values: SQLiteUpdateSetSource, + ): SQLiteEffectUpdateWithout< + SQLiteEffectUpdateBase, + false, + "leftJoin" | "rightJoin" | "innerJoin" | "fullJoin" + > { + return new SQLiteEffectUpdateBase( + this.table, + mapUpdateSet(this.table, values), + this.session, + this.dialect, + this.withList, + ) as any + } +} + +export interface SQLiteEffectUpdateBase< + TTable extends SQLiteTable = SQLiteTable, + TRunResult = unknown, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, + TReturning = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, +> extends SQLWrapper, + RunnableQuery, + Effect.Effect< + TReturning extends undefined ? TRunResult : TReturning[], + TEffectHKT["error"], + TEffectHKT["context"] + > { + readonly _: { + readonly dialect: "sqlite" + readonly table: TTable + readonly resultType: "async" + readonly runResult: TRunResult + readonly from: TFrom + readonly returning: TReturning + readonly dynamic: TDynamic + readonly excludedMethods: _TExcludedMethods + readonly result: TReturning extends undefined ? TRunResult : TReturning[] + readonly effectHKT: TEffectHKT + } +} + +export class SQLiteEffectUpdateBase< + TTable extends SQLiteTable = SQLiteTable, + TRunResult = unknown, + TFrom extends SQLiteTable | Subquery | SQLiteViewBase | SQL | undefined = undefined, + TReturning = undefined, + TDynamic extends boolean = false, + _TExcludedMethods extends string = never, + TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase, + > + implements RunnableQuery, SQLWrapper +{ + static readonly [entityKind]: string = "SQLiteEffectUpdate" + + /** @internal */ + config: SQLiteUpdateConfig + + constructor( + table: TTable, + set: UpdateSet, + private effectSession: SQLiteEffectSession, + private effectDialect: SQLiteDialect, + withList?: Subquery[], + ) { + this.config = { set, table, withList, joins: [] } + } + + from( + source: TFrom, + ): SQLiteEffectUpdateWithJoins { + this.config.from = source + return this as any + } + + private createJoin( + joinType: TJoinType, + ): SQLiteEffectUpdateJoinFn { + return (( + table: SQLiteTable | Subquery | SQLiteViewBase | SQL, + on: ((updateTable: TTable, from: TFrom) => SQL | undefined) | SQL | undefined, + ) => { + const tableName = getTableLikeName(table) + + if (typeof tableName === "string" && this.config.joins.some((join) => join.alias === tableName)) { + throw new Error(`Alias "${tableName}" is already used in this query`) + } + + if (typeof on === "function") { + const from = this.config.from + ? is(table, SQLiteTable) + ? getTableColumnsRuntime(table) + : is(table, Subquery) + ? table._.selectedFields + : is(table, SQLiteViewBase) + ? getViewSelectedFieldsRuntime(table).selectedFields + : undefined + : undefined + on = on( + new Proxy( + this.config.table._.columns, + new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" }), + ) as any, + from && + (new Proxy(from, new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })) as any), + ) + } + + this.config.joins.push({ on, table, joinType, alias: tableName }) + + return this as any + }) as any + } + + leftJoin = this.createJoin("left") + + rightJoin = this.createJoin("right") + + innerJoin = this.createJoin("inner") + + fullJoin = this.createJoin("full") + + where(where: SQL | undefined): SQLiteEffectUpdateWithout { + this.config.where = where + return this as any + } + + orderBy( + builder: (updateTable: TTable) => ValueOrArray, + ): SQLiteEffectUpdateWithout + orderBy(...columns: (SQLiteColumn | SQL | SQL.Aliased)[]): SQLiteEffectUpdateWithout + orderBy( + ...columns: + | [(updateTable: TTable) => ValueOrArray] + | (SQLiteColumn | SQL | SQL.Aliased)[] + ): SQLiteEffectUpdateWithout { + if (typeof columns[0] === "function") { + const orderBy = columns[0]( + new Proxy( + getTableColumnsRuntime(this.config.table), + new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" }), + ) as any, + ) + + this.config.orderBy = Array.isArray(orderBy) ? orderBy : [orderBy] + return this as any + } + + this.config.orderBy = columns as (SQLiteColumn | SQL | SQL.Aliased)[] + return this as any + } + + limit(limit: number | Placeholder): SQLiteEffectUpdateWithout { + this.config.limit = limit + return this as any + } + + returning(): SQLiteEffectUpdateReturningAll + returning( + fields: TSelectedFields, + ): SQLiteEffectUpdateReturning + returning( + fields: SelectedFields = getTableColumnsRuntime(this.config.table), + ): SQLiteEffectUpdateWithout { + this.config.returning = orderSelectedFields(fields) + return this as any + } + + /** @internal */ + getSQL(): SQL { + return this.effectDialect.buildUpdateQuery(this.config) + } + + toSQL(): Query { + return this.effectDialect.sqlToQuery(this.getSQL()) + } + + /** @internal */ + _prepare(isOneTimeQuery = true): SQLiteEffectUpdatePrepare { + return this.effectSession[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"]( + this.effectDialect.sqlToQuery(this.getSQL()), + this.config.returning, + this.config.returning ? "all" : "run", + undefined, + { + type: "update", + tables: extractUsedTable(this.config.table), + }, + ) as SQLiteEffectUpdatePrepare + } + + prepare(): SQLiteEffectUpdatePrepare { + return this._prepare(false) + } + + run: ReturnType["run"] = (placeholderValues) => { + return this._prepare().run(placeholderValues) + } + + all: ReturnType["all"] = (placeholderValues) => { + return this._prepare().all(placeholderValues) + } + + get: ReturnType["get"] = (placeholderValues) => { + return this._prepare().get(placeholderValues) + } + + values: ReturnType["values"] = (placeholderValues) => { + return this._prepare().values(placeholderValues) + } + + execute: ReturnType["execute"] = (placeholderValues) => { + return this._prepare().execute(placeholderValues) + } + + $dynamic(): SQLiteEffectUpdateDynamic { + return this as any + } +} + +applyEffectWrapper(SQLiteEffectUpdateBase) diff --git a/packages/effect-drizzle-sqlite/src/up-migrations/effect-sqlite.ts b/packages/effect-drizzle-sqlite/src/up-migrations/effect-sqlite.ts new file mode 100644 index 0000000000..3418752271 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/up-migrations/effect-sqlite.ts @@ -0,0 +1,102 @@ +/* oxlint-disable */ +import * as Effect from "effect/Effect" +import type { SqlError } from "effect/unstable/sql/SqlError" +import { EffectDrizzleError } from "drizzle-orm/effect-core/errors" +import type { QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" +import type { MigrationMeta } from "drizzle-orm/migrator" +import { sql } from "drizzle-orm/sql/sql" +import type { SQLiteEffectSession } from "../sqlite-core/effect/session" +import { + buildSQLiteMigrationBackfillStatements, + prepareSQLiteMigrationBackfill, + type SQLiteMigrationTableRow, +} from "./sqlite" +import { GET_VERSION_FOR, MIGRATIONS_TABLE_VERSIONS, type UpgradeResult } from "./utils" + +const migrationUpgradeError = (cause: unknown) => + new EffectDrizzleError({ + message: + typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string" + ? cause.message + : String(cause), + cause, + }) + +export const upgradeIfNeeded: ( + migrationsTable: string, + session: SQLiteEffectSession, + localMigrations: MigrationMeta[], +) => Effect.Effect = + Effect.fn("upgradeIfNeeded")(function* ( + migrationsTable: string, + session: SQLiteEffectSession, + localMigrations: MigrationMeta[], + ) { + const tableExists = yield* session.all( + sql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`, + ) + + if (tableExists.length === 0) { + return { newDb: true } + } + + const rows = yield* session.all<{ column_name: string }>( + sql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`, + ) + + const version = GET_VERSION_FOR.sqlite(rows.map((r) => r.column_name)) + + for (let v = version; v < MIGRATIONS_TABLE_VERSIONS.sqlite; v++) { + const upgradeFn = upgradeFunctions[v] + if (!upgradeFn) { + return yield* new EffectDrizzleError({ + message: `No upgrade path from migration table version ${v} to ${v + 1}`, + cause: { version: v }, + }) + } + yield* upgradeFn(migrationsTable, session, localMigrations) + } + + return { newDb: false } + }) + +const upgradeFunctions: Record< + number, + ( + migrationsTable: string, + session: SQLiteEffectSession, + localMigrations: MigrationMeta[], + ) => Effect.Effect +> = { + 0: upgradeFromV0, +} + +function upgradeFromV0( + migrationsTable: string, + session: SQLiteEffectSession, + localMigrations: MigrationMeta[], +): Effect.Effect { + return Effect.gen(function* () { + const table = sql`${sql.identifier(migrationsTable)}` + + const dbRows = yield* session.all( + sql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`, + ) + const statements = yield* Effect.try({ + try: () => + buildSQLiteMigrationBackfillStatements( + migrationsTable, + prepareSQLiteMigrationBackfill(dbRows, localMigrations), + ), + catch: migrationUpgradeError, + }) + + yield* session.transaction((tx) => + Effect.gen(function* () { + for (const statement of statements) { + yield* tx.run(statement) + } + }), + ) + }) +} diff --git a/packages/effect-drizzle-sqlite/src/up-migrations/sqlite.ts b/packages/effect-drizzle-sqlite/src/up-migrations/sqlite.ts new file mode 100644 index 0000000000..2887c66bed --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/up-migrations/sqlite.ts @@ -0,0 +1,253 @@ +/* oxlint-disable */ +import type { TablesRelationalConfig } from "drizzle-orm/_relations" +import type { MigrationMeta } from "drizzle-orm/migrator" +import type { AnyRelations } from "drizzle-orm/relations" +import { type SQL, sql } from "drizzle-orm/sql/sql" +import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core" +import type { SQLiteSession } from "drizzle-orm/sqlite-core/session" +import { GET_VERSION_FOR, MIGRATIONS_TABLE_VERSIONS, type UpgradeResult } from "./utils" + +/** @internal */ +export type SQLiteMigrationTableRow = { id: number | null; hash: string; created_at: number } + +type AsyncSQLiteDatabaseWithSession = BaseSQLiteDatabase<"async", unknown, Record> & { + session: { + all(query: SQL): Promise + } + transaction(transaction: (tx: { run(query: SQL): Promise }) => Promise): Promise +} + +type SQLiteMigrationBackfillEntry = { + name: string + selector: + | { column: "id"; value: number } + | { column: "created_at"; value: number } + | { column: "hash"; value: string } +} + +function unmatchedMigrationError(unmatched: SQLiteMigrationTableRow[]) { + return new Error( + `While upgrading your database migrations table we found ${unmatched.length} (${unmatched + .map((it) => `[id: ${it.id}, created_at: ${it.created_at}]`) + .join( + ", ", + )}) migrations in the database that do not match any local migration. This means that some migrations were applied to the database but are missing from the local environment`, + ) +} + +/** @internal */ +export function prepareSQLiteMigrationBackfill( + dbRows: SQLiteMigrationTableRow[], + localMigrations: MigrationMeta[], +): SQLiteMigrationBackfillEntry[] { + const sortedLocalMigrations = [...localMigrations].sort((a, b) => + a.folderMillis !== b.folderMillis ? a.folderMillis - b.folderMillis : (a.name ?? "").localeCompare(b.name ?? ""), + ) + const byMillis = new Map() + const byHash = new Map() + for (const migration of sortedLocalMigrations) { + if (!byMillis.has(migration.folderMillis)) { + byMillis.set(migration.folderMillis, []) + } + byMillis.get(migration.folderMillis)!.push(migration) + byHash.set(migration.hash, migration) + } + + const toApply: SQLiteMigrationBackfillEntry[] = [] + const unmatched: SQLiteMigrationTableRow[] = [] + + for (const dbRow of dbRows) { + const stringified = String(dbRow.created_at) + const millis = Number(stringified.substring(0, stringified.length - 3) + "000") + const candidates = byMillis.get(millis) + + const matchedByMillis = candidates?.length === 1 ? candidates[0] : undefined + const matchedByCandidateHash = + candidates && candidates.length > 1 + ? candidates.find((candidate) => candidate.hash && dbRow.hash && candidate.hash === dbRow.hash) + : undefined + const matchedByHash = matchedByMillis || matchedByCandidateHash ? undefined : byHash.get(dbRow.hash) + const matched = matchedByMillis ?? matchedByCandidateHash ?? matchedByHash + + if (matched) { + toApply.push({ + name: matched.name, + selector: + dbRow.id !== null + ? { column: "id", value: dbRow.id } + : matchedByMillis + ? { column: "created_at", value: dbRow.created_at } + : { column: "hash", value: dbRow.hash }, + }) + continue + } + + unmatched.push(dbRow) + } + + if (unmatched.length > 0) { + throw unmatchedMigrationError(unmatched) + } + + return toApply +} + +/** @internal */ +export function buildSQLiteMigrationBackfillStatements( + migrationsTable: string, + backfillEntries: SQLiteMigrationBackfillEntry[], +) { + const table = sql`${sql.identifier(migrationsTable)}` + const statements: SQL[] = [ + sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("name")} text`, + sql`ALTER TABLE ${table} ADD COLUMN ${sql.identifier("applied_at")} TEXT`, + ] + + for (const backfillEntry of backfillEntries) { + const updateQuery = sql`UPDATE ${table} SET ${sql.identifier("name")} = ${backfillEntry.name}, ${sql.identifier( + "applied_at", + )} = NULL WHERE` + + updateQuery.append(sql` ${sql.identifier(backfillEntry.selector.column)} = ${backfillEntry.selector.value}`) + + statements.push(updateQuery) + } + + return statements +} + +/** + * Detects the current version of the migrations table schema and upgrades it if needed. + * + * Version 0: Original schema (id, hash, created_at) + * Version 1: Extended schema (id, hash, created_at, name, applied_at) + */ +export function upgradeSyncIfNeeded( + migrationsTable: string, + session: SQLiteSession<"sync", unknown, Record, AnyRelations, TablesRelationalConfig>, + localMigrations: MigrationMeta[], +): UpgradeResult { + const tableExists = session.all(sql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`) + + if (tableExists.length === 0) { + return { newDb: true } + } + + // Table exists, check table shape + const rows = session.all<{ column_name: string }>( + sql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`, + ) + + const version = GET_VERSION_FOR.sqlite(rows.map((r) => r.column_name)) + + for (let v = version; v < MIGRATIONS_TABLE_VERSIONS.sqlite; v++) { + const upgradeFn = upgradeSyncFunctions[v] + if (!upgradeFn) { + throw new Error(`No upgrade path from migration table version ${v} to ${v + 1}`) + } + upgradeFn(migrationsTable, session, localMigrations) + } + + return { newDb: false } +} + +const upgradeSyncFunctions: Record< + number, + ( + migrationsTable: string, + session: SQLiteSession<"sync", unknown, Record, AnyRelations, TablesRelationalConfig>, + localMigrations: MigrationMeta[], + ) => void +> = { + /** + * Upgrade from version 0 to version 1: + * 1. Read all existing DB migrations + * 2. Sort localMigrations ASC by millis and if the same - sort by name + * 3. Match each DB row to a local migration + * If multiple migrations share the same second, use hash matching as a tiebreaker + * Not implemented for now -> If hash matching fails, fall back to serial id ordering + * 5. Create extra column and backfill names for matched migrations + */ + 0: (migrationsTable, session, localMigrations) => { + const table = sql`${sql.identifier(migrationsTable)}` + const dbRows = session.all(sql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`) + const statements = buildSQLiteMigrationBackfillStatements( + migrationsTable, + prepareSQLiteMigrationBackfill(dbRows, localMigrations), + ) + + session.transaction((tx) => { + for (const statement of statements) { + tx.run(statement) + } + }) + }, +} + +/** + * Detects the current version of the migrations table schema and upgrades it if needed. + * + * Version 0: Original schema (id, hash, created_at) + * Version 1: Extended schema (id, hash, created_at, name, applied_at) + */ +export async function upgradeAsyncIfNeeded( + migrationsTable: string, + db: AsyncSQLiteDatabaseWithSession, + localMigrations: MigrationMeta[], +): Promise { + // Check if the table exists at all + const tableExists = await db.session.all( + sql`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ${migrationsTable}`, + ) + + if (tableExists.length === 0) { + return { newDb: true } + } + + const rows = await db.session.all<{ column_name: string }>( + sql`SELECT name as column_name FROM pragma_table_info(${migrationsTable})`, + ) + + const version = GET_VERSION_FOR.sqlite(rows.map((r) => r.column_name)) + + for (let v = version; v < MIGRATIONS_TABLE_VERSIONS.sqlite; v++) { + const upgradeFn = upgradeAsyncFunctions[v] + if (!upgradeFn) { + throw new Error(`No upgrade path from migration table version ${v} to ${v + 1}`) + } + await upgradeFn(migrationsTable, db, localMigrations) + } + + return { newDb: false } +} + +const upgradeAsyncFunctions: Record< + number, + (migrationsTable: string, db: AsyncSQLiteDatabaseWithSession, localMigrations: MigrationMeta[]) => Promise +> = { + /** + * Upgrade from version 0 to version 1: + * 1. Read all existing DB migrations + * 2. Sort localMigrations ASC by millis and if the same - sort by name + * 3. Match each DB row to a local migration + * If multiple migrations share the same second, use hash matching as a tiebreaker + * Not implemented for now -> If hash matching fails, fall back to serial id ordering + * 5. Create extra column and backfill names for matched migrations + */ + 0: async (migrationsTable, db, localMigrations) => { + const table = sql`${sql.identifier(migrationsTable)}` + const dbRows = await db.session.all( + sql`SELECT id, hash, created_at FROM ${table} ORDER BY id ASC`, + ) + const statements = buildSQLiteMigrationBackfillStatements( + migrationsTable, + prepareSQLiteMigrationBackfill(dbRows, localMigrations), + ) + + await db.transaction(async (tx) => { + for (const statement of statements) { + await tx.run(statement) + } + }) + }, +} diff --git a/packages/effect-drizzle-sqlite/src/up-migrations/utils.ts b/packages/effect-drizzle-sqlite/src/up-migrations/utils.ts new file mode 100644 index 0000000000..cc71213ac4 --- /dev/null +++ b/packages/effect-drizzle-sqlite/src/up-migrations/utils.ts @@ -0,0 +1,45 @@ +/* oxlint-disable */ +export interface UpgradeResult { + newDb: boolean +} + +export const MIGRATIONS_TABLE_VERSIONS = { + sqlite: 1, + pg: 1, + effect: 1, + mysql: 1, + mssql: 1, + cockroach: 1, + singlestore: 1, +} as const + +export const GET_VERSION_FOR = { + mysql: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + pg: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + effect: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + mssql: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + cockroach: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + singlestore: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, + sqlite: (columns: string[]): number => { + if (columns.includes("name")) return 1 + return 0 + }, +} as const diff --git a/packages/effect-drizzle-sqlite/sst-env.d.ts b/packages/effect-drizzle-sqlite/sst-env.d.ts new file mode 100644 index 0000000000..64441936d7 --- /dev/null +++ b/packages/effect-drizzle-sqlite/sst-env.d.ts @@ -0,0 +1,10 @@ +/* This file is auto-generated by SST. Do not edit. */ +/* tslint:disable */ +/* eslint-disable */ +/* deno-fmt-ignore-file */ +/* biome-ignore-all lint: auto-generated */ + +/// + +import "sst" +export {} \ No newline at end of file diff --git a/packages/effect-drizzle-sqlite/test/sqlite.test.ts b/packages/effect-drizzle-sqlite/test/sqlite.test.ts new file mode 100644 index 0000000000..69e6ebed2e --- /dev/null +++ b/packages/effect-drizzle-sqlite/test/sqlite.test.ts @@ -0,0 +1,139 @@ +import { mkdir, mkdtemp, rm } from "node:fs/promises" +import { tmpdir } from "node:os" +import { join } from "node:path" +import { expect, test } from "bun:test" +import { SqliteClient } from "@effect/sql-sqlite-bun" +import { eq, sql } from "drizzle-orm" +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core" +import { Effect } from "effect" +import type { SqlClient as SqlClientService } from "effect/unstable/sql/SqlClient" +import { EffectDrizzleSqlite } from "../src" + +const users = sqliteTable("users", { + id: integer().primaryKey({ autoIncrement: true }), + name: text().notNull(), +}) + +const run = (effect: Effect.Effect) => + Effect.runPromise( + effect.pipe(Effect.provide(SqliteClient.layer({ filename: ":memory:", disableWAL: true })), Effect.scoped), + ) + +const makeDb = Effect.gen(function* () { + const db = yield* EffectDrizzleSqlite.makeWithDefaults() + yield* db.run(sql`create table users (id integer primary key autoincrement, name text not null)`) + return db +}) + +const createMigrationsFolder = async () => { + const migrationsFolder = await mkdtemp(join(tmpdir(), "effect-drizzle-sqlite-")) + await mkdir(join(migrationsFolder, "20240101000000_create_migrated_users"), { recursive: true }) + await Bun.write( + join(migrationsFolder, "20240101000000_create_migrated_users", "migration.sql"), + "create table migrated_users (id integer primary key autoincrement, name text not null);", + ) + return migrationsFolder +} + +test("selects rows through Effect-yieldable query builders", async () => { + await run( + Effect.gen(function* () { + const db = yield* makeDb + yield* db.insert(users).values({ name: "Ada" }) + + expect(yield* db.select().from(users)).toEqual([{ id: 1, name: "Ada" }]) + expect(yield* db.select({ id: users.id }).from(users).where(eq(users.name, "Ada")).get()).toEqual({ id: 1 }) + }), + ) +}) + +test("commits successful transactions", async () => { + await run( + Effect.gen(function* () { + const db = yield* makeDb + + yield* db.transaction((tx) => tx.insert(users).values({ name: "Grace" }), { behavior: "immediate" }) + + expect(yield* db.select().from(users)).toEqual([{ id: 1, name: "Grace" }]) + }), + ) +}) + +test("rolls back failed transactions", async () => { + await run( + Effect.gen(function* () { + const db = yield* makeDb + + yield* db + .transaction((tx) => + tx + .insert(users) + .values({ name: "Linus" }) + .pipe(Effect.andThen(Effect.fail("boom"))), + ) + .pipe(Effect.ignore) + + expect(yield* db.select().from(users)).toEqual([]) + }), + ) +}) + +test("rolls back explicit transaction rollback", async () => { + await run( + Effect.gen(function* () { + const db = yield* makeDb + + yield* db + .transaction((tx) => + tx + .insert(users) + .values({ name: "Barbara" }) + .pipe(Effect.andThen(Effect.fail(tx.rollback()))), + ) + .pipe(Effect.ignore) + + expect(yield* db.select().from(users)).toEqual([]) + }), + ) +}) + +test("supports returning and rejects empty update sets", async () => { + await run( + Effect.gen(function* () { + const db = yield* makeDb + + const inserted = yield* db.insert(users).values({ name: "Ada" }).returning({ id: users.id, name: users.name }) + expect(inserted).toEqual([{ id: 1, name: "Ada" }]) + + const updated = yield* db.update(users).set({ name: "Grace" }).where(eq(users.id, 1)).returning() + expect(updated).toEqual([{ id: 1, name: "Grace" }]) + + const deleted = yield* db.delete(users).where(eq(users.id, 1)).returning({ id: users.id }) + expect(deleted).toEqual([{ id: 1 }]) + + expect(() => db.update(users).set({ name: undefined })).toThrow("No values to set") + }), + ) +}) + +test("runs migrations once and records migration metadata", async () => { + const migrationsFolder = await createMigrationsFolder() + try { + await run( + Effect.gen(function* () { + const db = yield* EffectDrizzleSqlite.makeWithDefaults() + + yield* EffectDrizzleSqlite.migrate(db, { migrationsFolder }) + yield* EffectDrizzleSqlite.migrate(db, { migrationsFolder }) + yield* db.run(sql`insert into migrated_users (name) values ('Margaret')`) + + expect(yield* db.all<{ name: string }>(sql`select name from migrated_users`)).toEqual([{ name: "Margaret" }]) + expect(yield* db.all<{ name: string | null }>(sql`select name from __drizzle_migrations`)).toEqual([ + { name: "20240101000000_create_migrated_users" }, + ]) + }), + ) + } finally { + await rm(migrationsFolder, { recursive: true, force: true }) + } +}) diff --git a/packages/effect-drizzle-sqlite/tsconfig.json b/packages/effect-drizzle-sqlite/tsconfig.json new file mode 100644 index 0000000000..2bc480ffbb --- /dev/null +++ b/packages/effect-drizzle-sqlite/tsconfig.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@tsconfig/bun/tsconfig.json", + "compilerOptions": { + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "noUncheckedIndexedAccess": false, + "plugins": [ + { + "name": "@effect/language-service", + "transform": "@effect/language-service/transform", + "namespaceImportPackages": ["effect", "@effect/*"] + } + ] + } +} diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index c339ebfb6e..c0c9940f35 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "7.3.42" +version = "7.3.46" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.46/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.46/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.46/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.46/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.42/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.46/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/http-recorder/package.json b/packages/http-recorder/package.json index f56ba06f6e..24c96c918d 100644 --- a/packages/http-recorder/package.json +++ b/packages/http-recorder/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.42", + "version": "7.3.46", "name": "@opencode-ai/http-recorder", "type": "module", "license": "MIT", diff --git a/packages/llm/AGENTS.md b/packages/llm/AGENTS.md index 16a58fd866..29cb71f1c4 100644 --- a/packages/llm/AGENTS.md +++ b/packages/llm/AGENTS.md @@ -10,7 +10,7 @@ ## Conventions -Per-type constructors live on the type's namespace, not as top-level re-exports. Use `Message.user(...)`, `Message.assistant(...)`, `Message.tool(...)`, `ToolDefinition.make(...)`, `ToolCallPart.make(...)`, `ToolResultPart.make(...)`, `ToolChoice.make(...)`, `ToolChoice.named(...)`, `SystemPart.make(...)`, and `GenerationOptions.make(...)` directly. The top-level `LLM` namespace is reserved for the request-shaped call API: `LLM.request`, `LLM.generate`, `LLM.stream`, `LLM.model`, `LLM.updateRequest`, `LLM.generateObject`. Two ways to construct the same thing is one too many. +Per-type constructors live on the type, not as top-level re-exports. Use `Message.user(...)`, `Message.assistant(...)`, `Message.tool(...)`, `Model.make(...)`, `ToolDefinition.make(...)`, `ToolCallPart.make(...)`, `ToolResultPart.make(...)`, `ToolChoice.make(...)`, `ToolChoice.named(...)`, `SystemPart.make(...)`, and `GenerationOptions.make(...)` directly. The top-level `LLM` namespace is reserved for request-shaped call APIs: `LLM.request`, `LLM.generate`, `LLM.stream`, `LLM.updateRequest`, and `LLM.generateObject`. Two ways to construct the same thing is one too many. ## Tests @@ -21,13 +21,22 @@ Per-type constructors live on the type's namespace, not as top-level re-exports. This package is an Effect Schema-first LLM core. The Schema classes in `src/schema/` are the canonical runtime data model. Convenience functions in `src/llm.ts` are thin constructors that return those same Schema class instances; they should improve callsites without creating a second model. +Primary in-repo integration point: + +- `packages/opencode/src/session/llm.ts` is the session-owned orchestration layer that decides whether a request uses AI SDK or this package's native route runtime. +- `packages/opencode/src/session/llm/native-request.ts` is the lowering adapter from opencode's session/AI SDK-shaped data into this package's `LLMRequest` model. +- `packages/opencode/src/session/llm/native-runtime.ts` is the execution adapter that calls `LLMClient.stream(...)` and bridges opencode tools into this package's tool runtime. +- `packages/opencode/src/session/llm/ai-sdk.ts` keeps the default AI SDK path compatible by converting AI SDK stream parts into this package's shared `LLMEvent`s. + +Keep this package independent of session concerns. Session auth, permissions, plugins, telemetry headers, and runtime selection belong in `packages/opencode/src/session/llm.ts` and its local adapters. + ### Request Flow The intended callsite is: ```ts const request = LLM.request({ - model: OpenAI.model("gpt-4o-mini", { apiKey }), + model: OpenAI.configure({ apiKey }).responses("gpt-4o-mini"), system: "You are concise.", prompt: "Say hello.", }) @@ -35,7 +44,7 @@ const request = LLM.request({ const response = yield * LLMClient.generate(request) ``` -`LLM.request(...)` builds an `LLMRequest`. `LLMClient.generate(...)` selects a registered route by `request.model.route`, builds the provider-native body, asks the route's transport for a real `HttpClientRequest.HttpClientRequest`, sends it through `RequestExecutor.Service`, parses the provider stream into common `LLMEvent`s, and finally returns an `LLMResponse`. +`LLM.request(...)` builds an `LLMRequest`. `LLMClient.generate(...)` reads the executable route carried by `request.model.route`, builds the provider-native body, asks the route's transport for a real `HttpClientRequest.HttpClientRequest`, sends it through `RequestExecutor.Service`, parses the provider stream into common `LLMEvent`s, and finally returns an `LLMResponse`. Use `LLMClient.stream(request)` when callers want incremental `LLMEvent`s. Use `LLMClient.generate(request)` when callers want those same events collected into an `LLMResponse`. Use `LLMClient.prepare(request)` to compile a request through the route pipeline without sending it — the optional `Body` type argument narrows `.body` to the route's native shape (e.g. `prepare(...)` returns a `PreparedRequestOf`). The runtime body is identical; the generic is a type-level assertion. @@ -46,8 +55,8 @@ Filter or narrow `LLMEvent` streams with `LLMEvent.is.*` (camelCase guards, e.g. A route is the registered, runnable composition of four orthogonal pieces: - **`Protocol`** (`src/route/protocol.ts`) — semantic API contract. Owns request body construction (`body.from`), the body schema (`body.schema`), the streaming-event schema (`stream.event`), and the event-to-`LLMEvent` state machine (`stream.step`). `Route.make(...)` validates and JSON-encodes the body from `body.schema` and decodes frames with `stream.event`. Examples: `OpenAIChat.protocol`, `OpenAIResponses.protocol`, `AnthropicMessages.protocol`, `Gemini.protocol`, `BedrockConverse.protocol`. -- **`Endpoint`** (`src/route/endpoint.ts`) — path construction. The host always lives on `model.baseURL`; the endpoint just supplies the path. `Endpoint.path("/chat/completions")` is the common case; pass a function for paths that embed the model id or a body field (e.g. `Endpoint.path(({ body }) => `/model/${body.modelId}/converse-stream`)`). -- **`Auth`** (`src/route/auth.ts`) — per-request transport authentication. Routes read `model.apiKey` at request time via `Auth.bearer` (the default; sets `Authorization: Bearer `) or `Auth.apiKeyHeader(name)` for providers that use a custom header (Anthropic `x-api-key`, Gemini `x-goog-api-key`). Routes that need per-request signing (Bedrock SigV4, future Vertex IAM, Azure AAD) implement `Auth` as a function that signs the body and merges signed headers into the result. +- **`Endpoint`** (`src/route/endpoint.ts`) — URL construction. The host, path, and route query live on the endpoint. `Endpoint.path("/chat/completions", { baseURL })` is the common case; pass a function for paths that embed the model id or a body field (e.g. `Endpoint.path(({ body }) => `/model/${body.modelId}/converse-stream`)`). +- **`Auth`** (`src/route/auth.ts`) — per-request transport authentication. Provider facades configure credentials onto the route before model selection, usually via `Auth.bearer(apiKey)` or `Auth.header(name, apiKey)`. Routes that need per-request signing (Bedrock SigV4, future Vertex IAM, Azure AAD) implement `Auth` as a function that signs the body and merges signed headers into the result. - **`Framing`** (`src/route/framing.ts`) — bytes → frames. SSE (`Framing.sse`) is shared; Bedrock keeps its AWS event-stream framing as a typed `Framing` value alongside its protocol. Compose them via `Route.make(...)`: @@ -57,55 +66,52 @@ export const route = Route.make({ id: "openai-chat", provider: "openai", protocol: OpenAIChat.protocol, - transport: HttpTransport.httpJson({ - endpoint: Endpoint.path("/chat/completions"), - auth: Auth.bearer(), - framing: Framing.sse, - encodeBody, - }), - defaults: { + endpoint: Endpoint.path("/chat/completions", { baseURL: "https://api.openai.com/v1", - capabilities: capabilities({ tools: { calls: true, streamingInput: true } }), - }, + }), + auth: Auth.bearer(), + framing: Framing.sse, }) ``` +Route defaults are request-shaping defaults such as `headers`, `limits`, `generation`, `providerOptions`, and `http`. Endpoint host/query belongs on the route endpoint. Selected `Model` values carry only model id, provider id, and the configured route value. Model capability/catalog metadata lives outside this package; protocol support is enforced by request lowering and typed `LLMError`s. + The four-axis decomposition is the reason DeepSeek, TogetherAI, Cerebras, Baseten, Fireworks, and DeepInfra all reuse `OpenAIChat.protocol` verbatim — each provider deployment is a 5-15 line `Route.make(...)` call instead of a 300-400 line route clone. Bug fixes in one protocol propagate to every consumer of that protocol in a single commit. -When a provider ships a non-HTTP transport (OpenAI's WebSocket Responses backend, hypothetical bidirectional streaming APIs), the seam is `Transport` — `WebSocketTransport.json(...)` constructs a transport whose `prepare` builds a WebSocket URL and message and whose `frames` yields decoded text from the socket. Same protocol, different transport. +When a provider ships a non-HTTP transport (OpenAI's WebSocket Responses backend, hypothetical bidirectional streaming APIs), the seam is `Transport` — `WebSocketTransport.jsonTransport.with(...)` constructs an IO template whose `prepare` receives the route endpoint/auth at compile time, builds a WebSocket URL and message, and whose `frames` yields decoded text from the socket. Same protocol and endpoint source, different transport. ### URL Construction -`model.baseURL` is required; `Endpoint` only carries the path. Each protocol's `Route.make` includes a canonical URL in `defaults.baseURL` (e.g. `https://api.openai.com/v1`); provider helpers can override by passing `baseURL` in their input. Routes that have no canonical URL (OpenAI-compatible Chat, GitHub Copilot) set `baseURL: string` (required) on their input type so TypeScript catches a missing host at the call site. +`Endpoint` owns `{ baseURL, path, query }`. Each protocol route includes a canonical endpoint when the provider has one (e.g. `https://api.openai.com/v1`); provider helpers override endpoint fields by configuring the route before selecting a model. Routes that have no canonical URL (OpenAI-compatible Chat, GitHub Copilot) require configuration before execution. -For providers where the URL is derived from typed inputs (Azure resource name, Bedrock region), the provider helper computes `baseURL` at model construction time. Use `AtLeastOne` from `route/auth-options.ts` for inputs that accept either of two derivation paths (Azure: `resourceName` or `baseURL`). +For providers where the URL is derived from typed inputs (Azure resource name, Bedrock region), the provider helper configures the route endpoint before calling `.model(...)`. Use `AtLeastOne` from `route/auth-options.ts` for inputs that accept either of two derivation paths (Azure: `resourceName` or `baseURL`). -### Provider Definitions +### Provider Facades -Provider-facing APIs are defined with `Provider.make(...)` from `src/provider.ts`: +Provider-facing APIs are configured facades over route values. Endpoint/auth/resource/API-version setup happens before model selection, and model selectors accept only a model or deployment id: ```ts -export const provider = Provider.make({ - id: ProviderID.make("openai"), - model: responses, - apis: { responses, chat }, -}) +const openai = OpenAI.configure({ apiKey, baseURL }) +const model = openai.responses("gpt-4o-mini") -export const model = provider.model -export const apis = provider.apis +const azure = Azure.configure({ resourceName, apiKey, apiVersion: "v1" }) +const deployment = azure.responses("my-deployment") + +const gateway = CloudflareAIGateway.configure({ accountId, gatewayId, gatewayApiKey, apiKey }) +const proxied = gateway.model("openai/gpt-4o-mini") ``` -Keep provider definitions small and explicit: +Keep provider facades small and explicit: -- Use only `id`, `model`, and optional `apis` in `Provider.make(...)`. - Use branded `ProviderID.make(...)` and `ModelID.make(...)` where ids are constructed directly. -- Use `model` for the default API path and `apis` for named provider-native alternatives such as OpenAI `responses` versus `chat`. -- Do not add author-facing `kind`, `version`, or `routes` fields. +- Use `model` for the default API path and named methods for provider-native alternatives such as OpenAI `responses`, `responsesWebSocket`, and `chat`. +- Put provider-specific setup on `.configure(...)`; do not add `model(id, overrides)` as a duplicate construction path. - Export lower-level `routes` arrays separately only when advanced internal wiring needs them. - Prefer `apiKey` as provider-specific sugar and `auth` as the explicit override; keep them mutually exclusive in provider option types with `ProviderAuthOption`. - Resolve `apiKey` → `Auth` with `AuthOptions.bearer(options, "_API_KEY")` (it honors an explicit `auth` override and falls back to `Auth.config(envVar)` so missing keys surface a typed `Authentication` error rather than a runtime crash). +- Use separate top-level facades for products with different required setup, such as `CloudflareAIGateway` and `CloudflareWorkersAI`. -Built-in providers are namespace modules from `src/providers/index.ts`, so aliases like `OpenAI.model(...)`, `OpenAI.responses(...)`, and `OpenAI.apis.chat(...)` are fine. External provider packages should default-export the `Provider.make(...)` result and may add named aliases if useful. +`Provider.make(...)` remains available for simple static provider definitions, but new built-in providers should prefer plain configured facades unless a helper removes real duplication without adding runtime behavior. ### Folder layout @@ -113,7 +119,7 @@ Built-in providers are namespace modules from `src/providers/index.ts`, so alias packages/llm/src/ schema/ canonical Schema model, split by concern ids.ts branded IDs, literal types, ProviderMetadata - options.ts Generation/Provider/Http options, Capabilities, Limits, ModelRef + options.ts Generation/Provider/Http options, Limits, Model, cache policy messages.ts content parts, Message, ToolDefinition, LLMRequest events.ts Usage, individual events, LLMEvent, PreparedRequest, LLMResponse errors.ts error reasons, LLMError, ToolFailure @@ -145,12 +151,12 @@ packages/llm/src/ providers/ openai-compatible.ts generic compatible helper + family model helpers openai-compatible-profile.ts family defaults (deepseek, togetherai, ...) - azure.ts / amazon-bedrock.ts / github-copilot.ts / google.ts / xai.ts / openai.ts / anthropic.ts / openrouter.ts + azure.ts / amazon-bedrock.ts / cloudflare.ts / github-copilot.ts / google.ts / xai.ts / openai.ts / anthropic.ts / openrouter.ts tool.ts typed tool() helper tool-runtime.ts implementation helpers for LLMClient tool execution ``` -The dependency arrow points down: `providers/*.ts` files import `protocols`, `endpoint`, `auth`, and `framing`; protocols do not import provider metadata. Lower-level modules know nothing about specific providers. +The dependency arrow points down: `providers/*.ts` files import protocol routes and auth-option utilities; protocol modules import `endpoint`, `auth`, `framing`, and transport pieces. Protocols do not import provider facades. Lower-level modules know nothing about provider catalog metadata. ### Shared protocol helpers @@ -245,14 +251,14 @@ Use this order for every protocol module: 5. Request body construction (`fromRequest`) 6. Stream parsing (`step` and per-event handlers) 7. Protocol and route -8. Model helper +8. Protocol route export ### Rules - Keep protocol files focused on the protocol. Move provider-specific projection, signing, media normalization, or other bulky transformations into `src/protocols/utils/*`. - Use `Effect.fn("Provider.fromRequest")` for request body construction entrypoints. Use `Effect.fn(...)` for event handlers that yield effects; keep purely synchronous handlers as plain functions returning a `StepResult` that the dispatcher lifts via `Effect.succeed(...)`. -- Parser state owns terminal information. The state machine records finish reason, usage, and pending tool calls; emit one terminal `request-finish` (or `provider-error`) when a `terminal` event arrives. If a provider splits reason and usage across events, merge them in parser state before flushing. -- Emit exactly one terminal `request-finish` event for a completed response. Use `stream.terminal` to signal the run is over and have `step` emit the final event. +- Parser state owns terminal information. The state machine records finish reason, usage, and pending tool calls; emit one terminal `finish` event (or `provider-error`) for each completed response. If a provider splits reason and usage across events, merge them in parser state before flushing. +- Emit exactly one terminal `finish` event for a completed response, normally after a matching `step-finish`. Use `stream.terminal` to stop reading when the provider has a completion sentinel; use `stream.onHalt` when the final event must be flushed after the framed stream ends. - Use shared helpers for repeated protocol policy such as text joining, usage totals, JSON parsing, and tool-call accumulation. `ToolStream` (`protocols/utils/tool-stream.ts`) accumulates streamed tool-call arguments uniformly. - Make intentional provider differences explicit in helper names or comments. If two protocol files differ visually, the reason should be obvious from the names. - Prefer dispatched per-event handlers (`onMessageStart`, `onContentBlockDelta`, ...) called from a small top-level `step` switch over a long if-chain. The dispatcher keeps the event surface visible at a glance. diff --git a/packages/llm/README.md b/packages/llm/README.md index 321bf715bb..020198dd64 100644 --- a/packages/llm/README.md +++ b/packages/llm/README.md @@ -7,7 +7,7 @@ import { Effect } from "effect" import { LLM, LLMClient } from "@opencode-ai/llm" import { OpenAI } from "@opencode-ai/llm/providers" -const model = OpenAI.model("gpt-4o-mini", { apiKey: process.env.OPENAI_API_KEY }) +const model = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY }).responses("gpt-4o-mini") const request = LLM.request({ model, @@ -28,10 +28,10 @@ Run `LLMClient.stream(request)` instead of `generate` when you want incremental - **`LLM.request({...})`** — build a provider-neutral `LLMRequest`. Accepts ergonomic inputs (`system: string`, `prompt: string`) that normalize into the canonical Schema classes. - **`LLM.generate` / `LLM.stream`** — re-exported from `LLMClient` for one-import use. -- **`LLM.user(...)` / `LLM.assistant(...)` / `LLM.toolMessage(...)`** — message constructors. -- **`LLM.toolCall(...)` / `LLM.toolResult(...)` / `LLM.toolDefinition(...)`** — tool-related parts. +- **`Message.user(...)` / `Message.assistant(...)` / `Message.tool(...)`** — message constructors from the canonical schema model. +- **`Model.make(...)` / `ToolCallPart.make(...)` / `ToolResultPart.make(...)` / `ToolDefinition.make(...)`** — model and tool-related constructors from the canonical schema model. - **`LLMClient.prepare(request)`** — compile a request through protocol body construction, validation, and HTTP preparation without sending. Useful for inspection and testing. -- **`LLMEvent.is.*`** — typed guards (`is.text`, `is.toolCall`, `is.requestFinish`, …) for filtering streams. +- **`LLMEvent.is.*`** — typed guards (`is.textDelta`, `is.toolCall`, `is.finish`, …) for filtering streams. ## Caching @@ -92,17 +92,19 @@ Normalized cache usage is read back into `response.usage.cacheReadInputTokens` a ## Providers -Each provider exports a `model(...)` helper that records identity, protocol, capabilities, auth, and defaults. +Provider facades configure endpoint/auth/deployment details first, then expose model selectors that take only a model or deployment id. The selected model carries the executable route value used at runtime. ```ts -import { Anthropic } from "@opencode-ai/llm/providers" +import { OpenAI, CloudflareAIGateway } from "@opencode-ai/llm/providers" -const model = Anthropic.model("claude-sonnet-4-6", { - apiKey: process.env.ANTHROPIC_API_KEY, -}) +const openai = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY }).responses("gpt-4o-mini") +const gateway = CloudflareAIGateway.configure({ + accountId: process.env.CLOUDFLARE_ACCOUNT_ID, + gatewayApiKey: process.env.CLOUDFLARE_API_TOKEN, +}).model("workers-ai/@cf/meta/llama-3.1-8b-instruct") ``` -Included providers: OpenAI, Anthropic, Google (Gemini), Amazon Bedrock, Azure OpenAI, Cloudflare, GitHub Copilot, OpenRouter, xAI, plus generic OpenAI-compatible helpers for DeepSeek, Cerebras, Groq, Fireworks, Together, etc. +Included providers: OpenAI, Anthropic, Google (Gemini), Amazon Bedrock, Azure OpenAI, Cloudflare AI Gateway, Cloudflare Workers AI, GitHub Copilot, OpenRouter, xAI, plus generic OpenAI-compatible helpers for DeepSeek, Cerebras, Groq, Fireworks, Together, etc. ## Provider options & HTTP overlays @@ -112,15 +114,15 @@ Three escape hatches in order of stability: 2. **`providerOptions: { : {...} }`** — typed-at-the-facade provider-specific knobs (OpenAI `promptCacheKey`, Anthropic `thinking`, Gemini `thinkingConfig`, OpenRouter routing). 3. **`http: { body, headers, query }`** — last-resort serializable overlays merged into the final HTTP request. Reach for this only when a stable typed path doesn't yet exist. -Model-level defaults are overridden by request-level values for each axis. +Route/provider defaults are overridden by request-level values for each axis. ## Routes -Adding a new model or deployment is usually 5–15 lines using `Route.make({ protocol, transport, ... })`. The four orthogonal pieces are protocol (body construction + stream parsing), transport (endpoint + auth + framing + encoding), defaults, and capabilities. See `AGENTS.md` for the architectural detail. +Adding a new model or deployment is usually 5-15 lines using `Route.make({ protocol, endpoint, auth, framing, ... })`. The route owns endpoint/auth/framing and the protocol owns body construction plus stream parsing. Transports are reusable IO templates that receive route endpoint/auth at compile time. Capability/catalog metadata lives outside this low-level package; unsupported request shapes fail during protocol lowering. See `AGENTS.md` for the architectural detail. ## Effect -This package is built on Effect. Public methods return `Effect` or `Stream`; provide `LLMClient.layer` (the default registers every shipped route) for runtime dispatch. The example at `example/tutorial.ts` is a runnable walkthrough. +This package is built on Effect. Public methods return `Effect` or `Stream`; provide `LLMClient.layer` for runtime dispatch and import the provider/protocol modules for the routes you use. The example at `example/tutorial.ts` is a runnable walkthrough. ## See also diff --git a/packages/llm/example/call-sites.md b/packages/llm/example/call-sites.md new file mode 100644 index 0000000000..093f74e51d --- /dev/null +++ b/packages/llm/example/call-sites.md @@ -0,0 +1,591 @@ +# LLM Call Site Sketches + +Scratchpad for examples first, abstractions second. Current direction: routes +execute, provider facades organize configured route sets, and models carry route +values directly. + +## Conversation Summary + +Kit and Aidan want provider-specific LLM behavior to move out of opencode's AI +SDK transform path and into `packages/llm` where possible. The goal is not a big +generic transform layer; the goal is small composable route definitions backed by +recorded golden tests. + +Things to keep testing against: + +- Cache placement: `cache: "auto"`, manual cache breakpoints, provider cache usage. +- Images: golden image tests for providers/protocols that claim image support. +- Reasoning: canonical reasoning parts/events versus provider-native knobs. +- Auth: bearer, custom headers, multiple credentials, query auth, SigV4, OAuth, no auth. +- OpenAI-compatible providers: DeepSeek, Together, Groq, Alibaba/DashScope, custom routers. +- Provider switching: stale signatures, encrypted reasoning, provider metadata, incompatible parts. +- Error quality: typed errors instead of generic SDK/server failures. + +## Final Guide: Routes Execute, Providers Organize + +Do not introduce a first-class `Deployment` abstraction unless it gains real +semantics. Provider facades are ergonomic configured route groups, not execution +registries. The executable/composable thing is still a route. Do not make route +construction publish to a global registry; models should carry their route value +directly. + +Keep durable identity separate from runtime capability: + +- Durable identity is small serializable data like `{ providerID, modelID }` for + config, sessions, logs, and catalogs. +- Runtime capability is a `Model` with a route value, protocol, transport, auth, + and defaults. It is allowed to contain functions and schemas. +- If persisted identity needs to become executable, resolve it through an app + boundary first. Do not make `LLMRequest` recover behavior from a global route + side table. + +Keep unconfigured behavior values as values, not factories. A transport like +`HttpTransport.sseJson` should be a reusable immutable value. Use a function only +when the caller supplies options or when construction needs fresh state. + +Use constants to remove repetition before inventing abstractions. Provider ids +are branded once per provider facade and reused across routes; a plain exported +object is enough for the provider-facing API unless a helper earns its keep by +removing repeated route projection. + +Expose default configured provider instances, and put provider-specific setup on +`.configure(...)`. Model selectors stay pure: `model(id)`, `responses(id)`, +`chat(id)`, etc. Endpoint/auth/resource/api-version configuration happens before +model selection, not as a second argument to model selection. + +Use provider/product facades consistently: + +- One coherent provider/product config surface gets one top-level facade. +- APIs/model kinds that share that config are methods on the facade. +- Different products with different required config get separate top-level + facades, not a shared namespace with unrelated children. +- Default facades are exposed only when concrete defaults or lazy env/credential + defaults make the facade valid. + +Examples: + +```ts +OpenAI.responses("gpt-4o") +OpenAI.chat("gpt-4o") +OpenAI.responsesWebSocket("gpt-4o") + +Azure.configure({ resourceName, apiKey }).responses("my-deployment") +AmazonBedrock.configure({ region, credentials }).model("anthropic.claude-3-5-sonnet-20241022-v2:0") + +CloudflareAIGateway.configure({ accountId, gatewayId, gatewayApiKey, apiKey }).model("openai/gpt-4o") +CloudflareWorkersAI.configure({ accountId, apiKey }).model("@cf/meta/llama-3.1-8b-instruct") + +OpenAICompatible.configure({ + provider: "custom", + baseURL: "https://custom.example/v1", + auth: Auth.bearer(apiKey), +}).model("custom-model") +``` + +Standardize the provider facade contract before abstracting construction. A +plain object is enough at first; add a helper only if repeated route projection +starts hiding the real provider-specific config. + +`Route.with(...)` patch semantics should be boring and explicit: + +- Omitted fields inherit from the original route. +- `endpoint` patches merge with the existing endpoint, so overriding `baseURL` + keeps the existing `path`. +- `endpoint.query` merges by default; later values win. +- `auth` replaces. +- `headers` merge by default; undefined values are omitted. +- `id` is optional in patches. Route ids are diagnostic/provider API labels, not + global runtime registry keys. + +1. **Route** + - route id + - provider id + - protocol + - body schema + - body builder + - stream event schema + - parser/state machine + - transport + - method / IO shape + - framing + - request preparation + - constants when unconfigured; functions only when configured + - endpoint + - base URL + - static path + - body/model-derived path + - query params + - auth + - bearer + - custom header + - multiple credentials + - SigV4 + - none + - defaults + - headers + - generation defaults + - provider options + - limits +2. **Provider Facade** + - default configured provider instance + - provider-specific `.configure(...)` + - plain object/function facade over one or more routes + - top-level export only when it represents one coherent config surface + - no passive `Provider.make(...)` wrapper unless it gains runtime behavior +3. **Model Selector** + - route/provider-owned selector + - accepts model id only + - returns executable models + - does not accept endpoint/auth/deployment overrides +4. **Model** + - model id + - route value + - provider id + - configured route value at selection time +5. **LLM Request** + - model + - messages/tools + - generation/cache/reasoning/response-format options + - request-level HTTP overlays for per-request headers/query/body additions, + not provider endpoint/auth reconfiguration +6. **Compile** + - read route from model + - merge route defaults and request overrides + - build final URL from route endpoint + - apply auth from the configured route + - build body with protocol + - execute with transport and parse with protocol + +## Provider Facade Shape + +The provider abstraction is a facade over configured routes, not the runtime +execution mechanism: + +```ts +type ProviderFacade = { + readonly id: ProviderID + readonly model: (id: string) => Model + readonly configure: (input?: Config) => ProviderFacade +} & APIs +``` + +Manual construction is fine and should be the default until duplication earns a +helper: + +```ts +export const OpenAI = { + id: openAIProvider, + model: openAIResponses.model, + responses: openAIResponses.model, + chat: openAIChat.model, + configure: configureOpenAI, +} satisfies ProviderFacade< + { + responses: (id: string) => Model + chat: (id: string) => Model + }, + OpenAIConfig +> +``` + +If several providers repeat the same projection from route values to model +methods, the helper can stay deliberately tiny: + +```ts +const configureOpenAI = (input: OpenAIConfig = {}) => + Provider.define({ + id: openAIProvider, + routes: { + responses: openAIResponses.with(openAIConfig(input)), + chat: openAIChat.with(openAIConfig(input)), + }, + default: "responses", + configure: configureOpenAI, + }) + +export const OpenAI = configureOpenAI() +``` + +`Provider.define(...)` would only project route methods and preserve types: + +```ts +OpenAI.model("gpt-4o") +OpenAI.responses("gpt-4o") +OpenAI.chat("gpt-4o") +OpenAI.configure({ apiKey }).responses("gpt-4o") +``` + +It must not register routes, select routes dynamically, or participate in +execution. Execution still reads the route value carried by the model. + +## Ideal Call Sites + +Define concrete routes for a native provider, then project them through a +provider facade: + +```ts +const openAIProvider = ProviderID.make("openai") + +const openAIResponses = Route.make({ + id: "openai-responses", + provider: openAIProvider, + protocol: OpenAIResponses.protocol, + transport: HttpTransport.sseJson, + endpoint: { + baseURL: "https://api.openai.com/v1", + path: "/responses", + }, + auth: Auth.envBearer("OPENAI_API_KEY"), +}) + +const openAIChat = Route.make({ + id: "openai-chat", + provider: openAIProvider, + protocol: OpenAIChat.protocol, + transport: HttpTransport.sseJson, + endpoint: { + baseURL: "https://api.openai.com/v1", + path: "/chat/completions", + }, + auth: Auth.envBearer("OPENAI_API_KEY"), +}) + +const openAIResponsesWebSocket = openAIResponses.with({ + id: "openai-responses-websocket", + transport: WebSocketTransport.json, +}) + +const openAIConfig = (input: OpenAIConfig) => ({ + endpoint: input.endpoint, + auth: input.auth ?? (input.apiKey ? Auth.bearer(input.apiKey) : undefined), + headers: { + "OpenAI-Organization": input.organization, + "OpenAI-Project": input.project, + }, +}) + +const configureOpenAI = (input: OpenAIConfig = {}) => { + const responses = openAIResponses.with(openAIConfig(input)) + const responsesWebSocket = openAIResponsesWebSocket.with(openAIConfig(input)) + const chat = openAIChat.with(openAIConfig(input)) + + return { + id: openAIProvider, + responses: responses.model, + responsesWebSocket: responsesWebSocket.model, + chat: chat.model, + model: responses.model, + configure: configureOpenAI, + } +} + +export const OpenAI = configureOpenAI() +``` + +Specialize it functionally for concrete providers: + +```ts +const deepSeekProvider = ProviderID.make("deepseek") + +const deepseekChat = openAIChat.with({ + id: "deepseek-chat", + provider: deepSeekProvider, + endpoint: { + baseURL: "https://api.deepseek.com/v1", + }, + auth: Auth.envBearer("DEEPSEEK_API_KEY"), +}) + +const configureDeepSeek = (input: OpenAICompatibleConfig = {}) => { + const route = deepseekChat.with({ + endpoint: input.endpoint, + auth: input.auth ?? (input.apiKey ? Auth.bearer(input.apiKey) : undefined), + }) + + return { + id: deepSeekProvider, + model: route.model, + configure: configureDeepSeek, + } +} + +export const DeepSeek = { + id: deepSeekProvider, + model: deepseekChat.model, + configure: configureDeepSeek, +} +``` + +Provider-specific configuration happens before model selection: + +```ts +const deepseek = DeepSeek.configure({ + endpoint: { + baseURL: "https://proxy.example.com/v1", + }, + auth: Auth.bearer(apiKey), +}) + +const model = deepseek.model("deepseek-chat") +``` + +Final request call site stays boring: + +```ts +const response = + yield * + LLM.generate( + LLM.request({ + model: DeepSeek.model("deepseek-chat"), + prompt: "Hello.", + }), + ) +``` + +HTTP versus WebSocket is represented as named route selectors, not as model or +request overrides. Same protocol, different transport, different route: + +```ts +OpenAI.responses("gpt-4o") +OpenAI.responsesWebSocket("gpt-4o") +``` + +The client should not require a different public layer just because a selected +route uses WebSocket. Use one `LLMClient.layer` with HTTP and WebSocket runtime +capabilities available; routes that do not need WebSocket simply never touch it. +If a WebSocket route is selected in an environment without WebSocket support, +fail with a typed transport configuration error. + +Azure is a route specialization with auth/path/default changes plus input +mapping. The public API configures the Azure resource once, then selects +deployment ids with pure model selectors: + +```ts +const azureProvider = ProviderID.make("azure") + +const azureResponses = openAIResponses.with({ + id: "azure-openai-responses", + provider: azureProvider, + auth: Auth.envHeader("api-key", "AZURE_OPENAI_API_KEY"), +}) + +const configureAzure = (input: AzureConfig = {}) => { + const route = azureResponses.with({ + endpoint: { + baseURL: + input.baseURL ?? + Endpoint.envBaseURL( + "AZURE_RESOURCE_NAME", + (resourceName) => `https://${resourceName}.openai.azure.com/openai/v1`, + ), + query: { "api-version": input.apiVersion ?? "v1" }, + }, + auth: input.apiKey ? Auth.header("api-key", input.apiKey) : Auth.envHeader("api-key", "AZURE_OPENAI_API_KEY"), + }) + + return { + id: azureProvider, + model: route.model, + responses: route.model, + configure: configureAzure, + } +} + +export const Azure = configureAzure() + +const azure = Azure.configure({ + resourceName: "my-resource", + apiVersion: "v1", +}) + +const model = azure.responses("my-deployment") +``` + +Default provider facades are only valid when required configuration has a lazy +default source. `Azure.responses("my-deployment")` can be valid if endpoint +resolution reads `AZURE_RESOURCE_NAME` lazily and fails with a typed +configuration error when missing. If a provider has no sensible lazy default, +do not expose a default model selector; expose only a configured entrypoint. + +Cloudflare AI Gateway and Workers AI are separate product facades because their +configuration surfaces differ. Do not make a root `Cloudflare.configure(...)` +pretend there is one coherent Cloudflare provider configuration: + +```ts +const cloudflareProvider = ProviderID.make("cloudflare-ai-gateway") + +const cloudflareOpenAIChat = openAIChat.with({ + id: "cloudflare-ai-gateway-openai-chat", + provider: cloudflareProvider, + auth: Auth.bearerHeader("cf-aig-authorization").andThen(Auth.bearer()), +}) + +const configureCloudflareAIGateway = (input: CloudflareAIGatewayConfig) => { + const route = cloudflareOpenAIChat.with({ + endpoint: { + baseURL: `https://gateway.ai.cloudflare.com/v1/${input.accountId}/${input.gatewayId}/openai`, + }, + auth: Auth.bearerHeader("cf-aig-authorization", input.gatewayApiKey).andThen(Auth.bearer(input.apiKey)), + }) + + return { + id: cloudflareProvider, + model: (modelID: string) => route.model({ id: modelID }), + configure: configureCloudflareAIGateway, + } +} + +export const CloudflareAIGateway = { + id: cloudflareProvider, + configure: configureCloudflareAIGateway, +} + +const gateway = CloudflareAIGateway.configure({ + accountId: "account", + gatewayId: "gateway", + gatewayApiKey, + apiKey, +}) + +const model = gateway.model("openai/gpt-4o") +``` + +If a Cloudflare product gains a full lazy env default, it can expose a direct +selector too. Until then, omitting `CloudflareAIGateway.model(...)` makes missing +account/gateway configuration unrepresentable. + +opencode's dynamic runtime should construct executable models at its app +boundary instead of exposing a giant unstructured public model constructor or a +generic dynamic resolver: + +```ts +const model = + providerID === "azure" + ? Azure.configure(resolvedAzureConfig).responses(apiModelID) + : endpoint.websocket + ? OpenAI.responsesWebSocket(apiModelID) + : OpenAI.responses(apiModelID) +``` + +That boundary can branch on durable config/catalog metadata and call typed +provider APIs directly. Transport selection belongs there too: map metadata like +`endpoint.websocket` to `OpenAI.responsesWebSocket(apiModelID)`; otherwise use +the normal `OpenAI.responses(apiModelID)` route. The client runtime only executes +the route carried by the model. + +## Competitive Shape + +This follows the strongest parts of adjacent libraries: + +- AI SDK: configured provider instances expose provider-specific model methods. +- Effect AI: executable models carry provider requirements and can be resolved by + an app boundary. +- LiteLLM/opencode config: dynamic `providerID/modelID` branching belongs at the + app boundary, not in the typed public provider API or a global runtime + resolver. +- LangChain/LlamaIndex: constructor-style config plus model id is convenient, + but we avoid making model selection also configure endpoint/auth. + +The chosen split is: + +```txt +Route = execution mechanics +Provider facade = configured route group +Model = selected executable model carrying route value +App boundary = explicit durable-config -> typed-provider call +``` + +## What This Removes + +- No `Provider.make(...)` as a core abstraction. +- No `Provider.make(...)` wrapper just to bind an id to model functions. Use a + branded provider id constant and a plain exported provider facade. +- No `Deployment.define(...)` unless future examples force it. +- No global route registry as the normal execution path. +- No import side effects required before a model can execute. +- No duplicate `provider.id` object when selected models already carry provider + id. +- No `model(id, overrides)` escape hatch. Model selection takes the model id; + endpoint/auth/deployment customization happens by configuring the route first. +- No transport override on model/request. HTTP SSE versus WebSocket is a named + route selector such as `responses` versus `responsesWebSocket`. +- No separate public `LLMClient.layerWithWebSocket`. The runtime should expose one + client layer with the available transport capabilities. +- No executable `ModelRef`. The executable handle is `Model`; durable model + identity stays separate and cannot execute on its own. + +## Implementation Todo + +- [x] Replace the current executable `ModelRef` with `Model`. +- [x] Change `Model.route` to carry a route value, not a `RouteID` string. +- [ ] Keep a separate durable model identity type for persisted/session/catalog + data, likely `{ providerID, modelID }`, and make it clear that it cannot + execute without resolver context. +- [x] Change route model selectors so `route.model(id)` returns an executable + model with the route value attached, not a globally registered route id. +- [x] Remove the standalone `Route.model(route, defaults, mapInput)` helper; + configured route instances own model selection. +- [x] Remove endpoint/auth escape hatches from route model selection; callers must + configure endpoint/auth through `route.with(...)` or provider facades before + calling `.model(...)`. +- [x] Remove request-shaping defaults from `Model`; selected models now carry only + id, provider, and configured route while defaults live on routes or requests. +- [x] Rework `LLMClient.prepare` / `stream` / `generate` to read + `request.model.route` directly instead of calling `registeredRoute(...)`. +- [x] Remove `Route.make(...)` global registration from the normal execution + path; keep route ids only as diagnostics/provider API labels. +- [x] Model endpoint as `{ baseURL, path, query }` on routes, then remove the + current split where host/query live on the model and path lives in route + transport setup. +- [x] Define `Route.with(...)` with explicit patch semantics for endpoint merge, + query merge, header merge, auth replacement, and optional diagnostic id. +- [x] Make unconfigured transports reusable constants such as + `HttpTransport.sseJson`; keep transport functions only for configured/fresh + state construction. +- [x] Collapse the public WebSocket runtime split so one `LLMClient.layer` + exposes available transport capabilities and selected routes fail with typed + transport config errors when a required capability is missing. +- [x] Convert OpenAI provider APIs to provider-facade shape: + `OpenAI.configure(config).responses(id)`, `.chat(id)`, and + `.responsesWebSocket(id)`. +- [x] Convert Azure to a configured facade where resource/base URL/api version + setup happens before selecting deployment ids. +- [x] Split Cloudflare products into separate facades such as + `CloudflareAIGateway` and `CloudflareWorkersAI`; do not expose a shared root + config surface unless one product actually exists. +- [x] Migrate remaining built-in provider facades one at a time so configuration + happens before model selection and selectors accept only ids: + xAI, GitHub Copilot, OpenRouter, OpenAI-compatible families, Anthropic, + Google/Gemini, and Amazon Bedrock now use configured facades such as + `Provider.configure(options).model(id)` with named selectors where needed. +- [ ] Decide whether a tiny `Provider.define(...)` helper is warranted after two + or three provider conversions; start with plain objects if duplication is not + yet painful. +- [x] Update `packages/opencode/src/session/llm/native-request.ts` to construct + executable models at the session boundary with explicit provider facade + calls, mapping catalog metadata such as `endpoint.websocket` to the correct + named route selector. +- [ ] Update tests so direct route/provider tests assert route values are carried + by executable models, and opencode/native tests assert boundary-based route + selection. +- [ ] Remove compatibility exports or stale docs only after internal call sites + are migrated; do not keep duplicate constructor paths without an external + compatibility need. + +## Open Questions + +- Default facades with required setup: should providers like Azure and Bedrock + expose default model selectors only when all required setup has lazy env or + credential-chain defaults? If not, omit the default selector so missing config + is impossible at the type/API level. +- Lazy endpoint/auth values: should `Endpoint.envBaseURL(...)` and env-backed + auth produce typed configuration/authentication errors at compile/prepare time + or only when executing the transport? +- `Route.with(...)` clearing semantics: endpoint/query/header patches merge by + default, but what is the explicit way to remove an inherited value? +- Provider facade helper: keep plain objects until duplication hurts, or add a + tiny `Provider.define(...)` immediately to enforce shape and method projection? +- Auth shape: should auth stay as today's composable `Auth`, or split into an + auth placement/strategy and credential sources? +- Naming: is `baseURL` still the right endpoint field name, or should it be + `origin` / `urlPrefix` to clarify that route `path` is appended? diff --git a/packages/llm/example/tutorial.ts b/packages/llm/example/tutorial.ts index 37d747dd8d..50b925b875 100644 --- a/packages/llm/example/tutorial.ts +++ b/packages/llm/example/tutorial.ts @@ -1,6 +1,6 @@ import { Config, Effect, Formatter, Layer, Schema, Stream } from "effect" -import { LLM, LLMClient, Provider, ProviderID, Tool, type ProviderModelOptions } from "@opencode-ai/llm" -import { Route, Auth, Endpoint, Framing, Protocol, RequestExecutor } from "@opencode-ai/llm/route" +import { LLM, LLMClient, ProviderID, Tool } from "@opencode-ai/llm" +import { Route, Auth, Endpoint, Framing, Protocol, RequestExecutor, WebSocketExecutor } from "@opencode-ai/llm/route" import { OpenAI } from "@opencode-ai/llm/providers" /** @@ -18,18 +18,18 @@ const apiKey = Config.redacted("OPENAI_API_KEY") // 1. Pick a model. The provider helper records provider identity, protocol // choice, capabilities, deployment options, authentication, and defaults. -const model = OpenAI.model("gpt-4o-mini", { +const model = OpenAI.configure({ apiKey, generation: { maxTokens: 160 }, providerOptions: { openai: { store: false }, }, -}) +}).model("gpt-4o-mini") // 2. Build a provider-neutral request. This is useful when reusing one request // across generate and stream examples. // -// Options can live on both the model and the request: +// Options can live on both the configured route/provider facade and the request: // // - `generation`: common controls such as max tokens, temperature, topP/topK, // penalties, seed, and stop sequences. @@ -39,7 +39,7 @@ const model = OpenAI.model("gpt-4o-mini", { // - `http`: last-resort serializable overlays for final request body, headers, // and query params. Prefer typed `providerOptions` when a field is stable. // -// Model options are defaults. Request options override them for this call. +// Route/provider options are defaults. Request options override them for this call. const request = LLM.request({ model, system: "You are concise and practical.", @@ -193,19 +193,22 @@ const FakeProtocol = Protocol.make({ // axes that the protocol deliberately does not know: URL, auth, and framing. const FakeAdapter = Route.make({ id: "fake-echo", + provider: "fake-echo", protocol: FakeProtocol, - endpoint: Endpoint.path("/v1/echo"), + endpoint: Endpoint.path("/v1/echo", { baseURL: "https://fake.local" }), auth: Auth.passthrough, framing: Framing.sse, }) -// A provider module exports a Provider definition. The default `model` helper -// sets provider identity, protocol id, and the route id resolved by the registry. -const fakeEchoModel = Route.model(FakeAdapter, { provider: "fake-echo", baseURL: "https://fake.local" }) -const FakeEcho = Provider.make({ +// A provider module exports a configured facade. Configuration happens before +// model selection; model selectors accept ids only. +const FakeEcho = { id: ProviderID.make("fake-echo"), - model: (id: string, options: ProviderModelOptions = {}) => fakeEchoModel({ id, ...options }), -}) + configure: () => ({ + id: ProviderID.make("fake-echo"), + model: (id: string) => FakeAdapter.model({ id }), + }), +} // `LLMClient.prepare` is the lower-level inspection hook: it compiles through // body conversion, validation, endpoint, auth, and HTTP construction without @@ -213,7 +216,7 @@ const FakeEcho = Provider.make({ const inspectFakeProvider = Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: FakeEcho.model("tiny-echo"), + model: FakeEcho.configure().model("tiny-echo"), prompt: "Show me the provider pipeline.", }), ) @@ -227,7 +230,8 @@ const inspectFakeProvider = Effect.gen(function* () { // enabled at a time so the tutorial can demonstrate generate, prepare, stream, // or tool-loop behavior without spending tokens on every example. const requestExecutorLayer = RequestExecutor.defaultLayer -const llmClientLayer = LLMClient.layer.pipe(Layer.provide(requestExecutorLayer)) +const llmDeps = Layer.mergeAll(requestExecutorLayer, WebSocketExecutor.layer) +const llmClientLayer = LLMClient.layer.pipe(Layer.provide(llmDeps)) const program = Effect.gen(function* () { // yield* generateOnce @@ -237,6 +241,6 @@ const program = Effect.gen(function* () { // yield* generateStructuredObject // yield* generateDynamicObject.pipe(Effect.andThen((response) => Effect.sync(() => console.log(response.object)))) yield* streamWithTools -}).pipe(Effect.provide(Layer.mergeAll(requestExecutorLayer, llmClientLayer))) +}).pipe(Effect.provide(Layer.mergeAll(llmDeps, llmClientLayer))) Effect.runPromise(program) diff --git a/packages/llm/package.json b/packages/llm/package.json index d3839f53eb..aed5676ec1 100644 --- a/packages/llm/package.json +++ b/packages/llm/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.42", + "version": "7.3.46", "name": "@opencode-ai/llm", "type": "module", "license": "MIT", diff --git a/packages/llm/src/cache-policy.ts b/packages/llm/src/cache-policy.ts index 6ab7a049fe..60f96dc69a 100644 --- a/packages/llm/src/cache-policy.ts +++ b/packages/llm/src/cache-policy.ts @@ -97,7 +97,7 @@ const markMessages = ( } export const applyCachePolicy = (request: LLMRequest): LLMRequest => { - if (!RESPECTS_INLINE_HINTS.has(request.model.route)) return request + if (!RESPECTS_INLINE_HINTS.has(request.model.route.id)) return request const policy = resolve(request.cache) if (!policy.tools && !policy.system && !policy.messages) return request diff --git a/packages/llm/src/index.ts b/packages/llm/src/index.ts index acf73b360e..389bc263d2 100644 --- a/packages/llm/src/index.ts +++ b/packages/llm/src/index.ts @@ -1,4 +1,4 @@ -export { LLMClient, modelLimits, modelRef } from "./route/client" +export { LLMClient } from "./route/client" export { Auth } from "./route/auth" export { Provider } from "./provider" export type { @@ -6,7 +6,6 @@ export type { RouteRoutedModelInput, Interface as LLMClientShape, Service as LLMClientService, - ModelRefInput, } from "./route/client" export * from "./schema" export { Tool, ToolFailure, toDefinitions, tool } from "./tool" diff --git a/packages/llm/src/llm.ts b/packages/llm/src/llm.ts index 6f6728216b..33ec56f3e9 100644 --- a/packages/llm/src/llm.ts +++ b/packages/llm/src/llm.ts @@ -1,5 +1,5 @@ import { Effect, JsonSchema, Schema } from "effect" -import { LLMClient, modelLimits, modelRef, type ModelRefInput } from "./route/client" +import { LLMClient } from "./route/client" import { GenerationOptions, HttpOptions, @@ -9,16 +9,16 @@ import { LLMRequest, LLMResponse, Message, + type ModelInput as SchemaModelInput, SystemPart, ToolChoice, ToolDefinition, type ContentPart, - ToolCallPart, ToolResultPart, } from "./schema" import { make as makeTool, type ToolSchema } from "./tool" -export type ModelInput = ModelRefInput +export type ModelInput = SchemaModelInput export type MessageInput = Message.Input @@ -42,10 +42,6 @@ export type RequestInput = Omit< readonly http?: HttpOptions.Input } -export const limits = modelLimits - -export const model = modelRef - export const generate = LLMClient.generate export const stream = LLMClient.stream diff --git a/packages/llm/src/protocols/anthropic-messages.ts b/packages/llm/src/protocols/anthropic-messages.ts index e27af18426..060e2e091a 100644 --- a/packages/llm/src/protocols/anthropic-messages.ts +++ b/packages/llm/src/protocols/anthropic-messages.ts @@ -10,9 +10,11 @@ import { type CacheHint, type FinishReason, type LLMRequest, + type MediaPart, type ProviderMetadata, type ToolCallPart, type ToolDefinition, + type ToolResultContentPart, type ToolResultPart, } from "../schema" import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared" @@ -39,6 +41,17 @@ const AnthropicTextBlock = Schema.Struct({ }) type AnthropicTextBlock = Schema.Schema.Type +const AnthropicImageBlock = Schema.Struct({ + type: Schema.tag("image"), + source: Schema.Struct({ + type: Schema.tag("base64"), + media_type: Schema.String, + data: Schema.String, + }), + cache_control: Schema.optional(AnthropicCacheControl), +}) +type AnthropicImageBlock = Schema.Schema.Type + const AnthropicThinkingBlock = Schema.Struct({ type: Schema.tag("thinking"), thinking: Schema.String, @@ -84,15 +97,24 @@ const AnthropicServerToolResultBlock = Schema.Struct({ }) type AnthropicServerToolResultBlock = Schema.Schema.Type +// Anthropic accepts either a plain string or an ordered array of text/image +// blocks inside `tool_result.content`. The array form is required when a tool +// returns image bytes (screenshot, image search, etc.) so they can be passed +// to the model as proper image inputs instead of being JSON-stringified into +// the prompt — which silently inflates context by megabytes and can push the +// conversation over the model's token limit. +const AnthropicToolResultContent = Schema.Union([AnthropicTextBlock, AnthropicImageBlock]) + const AnthropicToolResultBlock = Schema.Struct({ type: Schema.tag("tool_result"), tool_use_id: Schema.String, - content: Schema.String, + content: Schema.Union([Schema.String, Schema.Array(AnthropicToolResultContent)]), is_error: Schema.optional(Schema.Boolean), cache_control: Schema.optional(AnthropicCacheControl), }) -const AnthropicUserBlock = Schema.Union([AnthropicTextBlock, AnthropicToolResultBlock]) +const AnthropicUserBlock = Schema.Union([AnthropicTextBlock, AnthropicImageBlock, AnthropicToolResultBlock]) +type AnthropicUserBlock = Schema.Schema.Type const AnthropicAssistantBlock = Schema.Union([ AnthropicTextBlock, AnthropicThinkingBlock, @@ -184,7 +206,13 @@ const AnthropicEvent = Schema.Struct({ content_block: Schema.optional(AnthropicStreamBlock), delta: Schema.optional(AnthropicStreamDelta), usage: Schema.optional(AnthropicUsage), - error: Schema.optional(Schema.Struct({ type: Schema.String, message: Schema.String })), + // `type` and `message` are both required per Anthropic's spec, but + // OpenAI-compatible proxies and gateway translations occasionally drop one + // or the other; mark them optional so a partial payload still parses and + // the parser can fall back to whichever field is populated. + error: Schema.optional( + Schema.Struct({ type: Schema.optional(Schema.String), message: Schema.optional(Schema.String) }), + ), }) type AnthropicEvent = Schema.Schema.Type @@ -272,6 +300,44 @@ const lowerServerToolResult = Effect.fn("AnthropicMessages.lowerServerToolResult return { type: wireType, tool_use_id: part.id, content: part.result.value } satisfies AnthropicServerToolResultBlock }) +const lowerImage = Effect.fn("AnthropicMessages.lowerImage")(function* (part: MediaPart) { + if (!part.mediaType.startsWith("image/")) + return yield* invalid(`Anthropic Messages user media content only supports images`) + return { + type: "image" as const, + source: { + type: "base64" as const, + media_type: part.mediaType, + data: ProviderShared.mediaBase64(part), + }, + } satisfies AnthropicImageBlock +}) + +// Tool results may carry structured text/images. Keep media as provider-native +// content instead of JSON-stringifying base64 into a prompt string. +const lowerToolResultContentItem = Effect.fn("AnthropicMessages.lowerToolResultContentItem")(function* ( + item: ToolResultContentPart, +) { + if (item.type === "text") return { type: "text" as const, text: item.text } satisfies AnthropicTextBlock + if (item.mediaType.startsWith("image/")) + return { + type: "image" as const, + source: { + type: "base64" as const, + media_type: item.mediaType, + data: ProviderShared.mediaBase64(item), + }, + } satisfies AnthropicImageBlock + return yield* invalid(`Anthropic Messages tool-result media content only supports images, got ${item.mediaType}`) +}) + +const lowerToolResultContent = Effect.fn("AnthropicMessages.lowerToolResultContent")(function* (part: ToolResultPart) { + // Text / json / error results stay as a string for backward compatibility + // with existing cassettes and provider expectations. + if (part.result.type !== "content") return ProviderShared.toolResultText(part) + return yield* Effect.forEach(part.result.value, lowerToolResultContentItem) +}) + const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* ( request: LLMRequest, breakpoints: Cache.Breakpoints, @@ -280,11 +346,17 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* ( for (const message of request.messages) { if (message.role === "user") { - const content: AnthropicTextBlock[] = [] + const content: AnthropicUserBlock[] = [] for (const part of message.content) { - if (!ProviderShared.supportsContent(part, ["text"])) - return yield* ProviderShared.unsupportedContent("Anthropic Messages", "user", ["text"]) - content.push({ type: "text", text: part.text, cache_control: cacheControl(breakpoints, part.cache) }) + if (part.type === "text") { + content.push({ type: "text", text: part.text, cache_control: cacheControl(breakpoints, part.cache) }) + continue + } + if (part.type === "media") { + content.push(yield* lowerImage(part)) + continue + } + return yield* ProviderShared.unsupportedContent("Anthropic Messages", "user", ["text", "media"]) } messages.push({ role: "user", content }) continue @@ -328,7 +400,7 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* ( content.push({ type: "tool_result", tool_use_id: part.id, - content: ProviderShared.toolResultText(part), + content: yield* lowerToolResultContent(part), is_error: part.result.type === "error" ? true : undefined, cache_control: cacheControl(breakpoints, part.cache), }) @@ -386,7 +458,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques tools, tool_choice: toolChoice, stream: true as const, - max_tokens: generation?.maxTokens ?? request.model.limits.output ?? 4096, + max_tokens: generation?.maxTokens ?? request.model.route.defaults.limits?.output ?? 4096, temperature: generation?.temperature, top_p: generation?.topP, top_k: generation?.topK, @@ -452,8 +524,8 @@ const mergeUsage = (left: Usage | undefined, right: Usage | undefined) => { totalTokens: ProviderShared.totalTokens(inputTokens, outputTokens, undefined), providerMetadata: { anthropic: { - ...(left.providerMetadata?.["anthropic"] ?? {}), - ...(right.providerMetadata?.["anthropic"] ?? {}), + ...left.providerMetadata?.["anthropic"], + ...right.providerMetadata?.["anthropic"], }, }, }) @@ -635,9 +707,18 @@ const onMessageDelta = (state: ParserState, event: AnthropicEvent): StepResult = return [{ ...state, lifecycle, usage }, events] } +// Prefix `error.type` so overloads, rate limits, and quota errors are visible +// even when the provider message is generic or empty. +const providerErrorMessage = (event: AnthropicEvent): string => { + const type = event.error?.type + const message = event.error?.message + if (type && message) return `${type}: ${message}` + return message || type || "Anthropic Messages stream error" +} + const onError = (state: ParserState, event: AnthropicEvent): StepResult => [ state, - [LLMEvent.providerError({ message: event.error?.message ?? "Anthropic Messages stream error" })], + [LLMEvent.providerError({ message: providerErrorMessage(event) })], ] const step = (state: ParserState, event: AnthropicEvent) => { @@ -673,19 +754,12 @@ export const protocol = Protocol.make({ export const route = Route.make({ id: ADAPTER, + provider: "anthropic", protocol, - endpoint: Endpoint.path(PATH), - auth: Auth.apiKeyHeader("x-api-key"), + endpoint: Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL }), + auth: Auth.none, framing: Framing.sse, headers: () => ({ "anthropic-version": "2023-06-01" }), }) -// ============================================================================= -// Model Helper -// ============================================================================= -export const model = Route.model(route, { - provider: "anthropic", - baseURL: DEFAULT_BASE_URL, -}) - export * as AnthropicMessages from "./anthropic-messages" diff --git a/packages/llm/src/protocols/bedrock-converse.ts b/packages/llm/src/protocols/bedrock-converse.ts index 7f5647c4a7..54eb7930f8 100644 --- a/packages/llm/src/protocols/bedrock-converse.ts +++ b/packages/llm/src/protocols/bedrock-converse.ts @@ -1,5 +1,5 @@ import { Effect, Schema } from "effect" -import { Route, type RouteModelInput } from "../route/client" +import { Route } from "../route/client" import { Endpoint } from "../route/endpoint" import { Protocol } from "../route/protocol" import { @@ -14,7 +14,7 @@ import { } from "../schema" import { BedrockEventStream } from "./bedrock-event-stream" import { JsonObject, optionalArray, ProviderShared } from "./shared" -import { BedrockAuth, type Credentials as BedrockCredentials } from "./utils/bedrock-auth" +import { BedrockAuth } from "./utils/bedrock-auth" import { BedrockCache } from "./utils/bedrock-cache" import { BedrockMedia } from "./utils/bedrock-media" import { Lifecycle } from "./utils/lifecycle" @@ -24,23 +24,6 @@ const ADAPTER = "bedrock-converse" export type { Credentials as BedrockCredentials } from "./utils/bedrock-auth" -// ============================================================================= -// Public Model Input -// ============================================================================= -export type BedrockConverseModelInput = RouteModelInput & { - /** - * Bearer API key (Bedrock's newer API key auth). Sets the `Authorization` - * header and bypasses SigV4 signing. Mutually exclusive with `credentials`. - */ - readonly apiKey?: string - /** - * AWS credentials for SigV4 signing. The route signs each request at - * `toHttp` time using `aws4fetch`. Mutually exclusive with `apiKey`. - */ - readonly credentials?: BedrockCredentials - readonly headers?: Record -} - // ============================================================================= // Request Body Schema // ============================================================================= @@ -61,6 +44,7 @@ type BedrockToolUseBlock = Schema.Schema.Type const BedrockToolResultContentItem = Schema.Union([ Schema.Struct({ text: Schema.String }), Schema.Struct({ json: Schema.Unknown }), + BedrockMedia.ImageBlock, ]) const BedrockToolResultBlock = Schema.Struct({ @@ -261,15 +245,33 @@ const lowerToolCall = (part: ToolCallPart): BedrockToolUseBlock => ({ }, }) -const lowerToolResult = (part: ToolResultPart): BedrockToolResultBlock => ({ - toolResult: { - toolUseId: part.id, - content: - part.result.type === "text" || part.result.type === "error" - ? [{ text: ProviderShared.toolResultText(part) }] - : [{ json: part.result.value }], - status: part.result.type === "error" ? "error" : "success", - }, +const lowerToolResultContent = Effect.fn("BedrockConverse.lowerToolResultContent")(function* (part: ToolResultPart) { + if (part.result.type === "text" || part.result.type === "error") + return [{ text: ProviderShared.toolResultText(part) }] + if (part.result.type === "json") return [{ json: part.result.value }] + + const content: Array> = [] + for (const item of part.result.value) { + if (item.type === "text") { + content.push({ text: item.text }) + continue + } + const media = yield* BedrockMedia.lower(item) + if (!("image" in media)) + return yield* ProviderShared.invalidRequest("Bedrock Converse only supports image media in tool results") + content.push(media) + } + return content +}) + +const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (part: ToolResultPart) { + return { + toolResult: { + toolUseId: part.id, + content: yield* lowerToolResultContent(part), + status: part.result.type === "error" ? "error" : "success", + }, + } satisfies BedrockToolResultBlock }) const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* ( @@ -331,7 +333,7 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* ( for (const part of message.content) { if (!ProviderShared.supportsContent(part, ["tool-result"])) return yield* ProviderShared.unsupportedContent("Bedrock Converse", "tool", ["tool-result"]) - content.push(lowerToolResult(part)) + content.push(yield* lowerToolResult(part)) const cachePoint = BedrockCache.block(breakpoints, part.cache) if (cachePoint) content.push(cachePoint) } @@ -597,11 +599,11 @@ export const protocol = Protocol.make({ export const route = Route.make({ id: ADAPTER, + provider: "bedrock", protocol, - // Bedrock's URL embeds the region in the host (set on `model.baseURL` by - // the provider helper from credentials) and the validated modelId in the - // path. We read the validated body so the URL matches the body that gets - // signed. + // Bedrock's URL embeds the region in the route endpoint host and the + // validated modelId in the path. We read the validated body so the URL + // matches the body that gets signed. endpoint: Endpoint.path( ({ body }) => `/model/${encodeURIComponent(body.modelId)}/converse-stream`, ), @@ -609,26 +611,6 @@ export const route = Route.make({ framing, }) -export const nativeCredentials = BedrockAuth.nativeCredentials - -const bedrockModel = Route.model( - route, - { - provider: "bedrock", - }, - { - mapInput: (input: BedrockConverseModelInput) => { - const { credentials, ...rest } = input - const region = credentials?.region ?? "us-east-1" - return { - ...rest, - baseURL: rest.baseURL ?? `https://bedrock-runtime.${region}.amazonaws.com`, - native: nativeCredentials(input.native, credentials), - } - }, - }, -) - -export const model = bedrockModel +export const sigV4Auth = BedrockAuth.sigV4 export * as BedrockConverse from "./bedrock-converse" diff --git a/packages/llm/src/protocols/gemini.ts b/packages/llm/src/protocols/gemini.ts index 6e0b82abba..5fe4dcc760 100644 --- a/packages/llm/src/protocols/gemini.ts +++ b/packages/llm/src/protocols/gemini.ts @@ -404,19 +404,14 @@ export const protocol = Protocol.make({ export const route = Route.make({ id: ADAPTER, + provider: "google", protocol, // Gemini's path embeds the model id and pins SSE framing at the URL level. - endpoint: Endpoint.path(({ request }) => `/models/${request.model.id}:streamGenerateContent?alt=sse`), - auth: Auth.apiKeyHeader("x-goog-api-key"), + endpoint: Endpoint.path(({ request }) => `/models/${request.model.id}:streamGenerateContent?alt=sse`, { + baseURL: DEFAULT_BASE_URL, + }), + auth: Auth.none, framing: Framing.sse, }) -// ============================================================================= -// Model Helper -// ============================================================================= -export const model = Route.model(route, { - provider: "google", - baseURL: DEFAULT_BASE_URL, -}) - export * as Gemini from "./gemini" diff --git a/packages/llm/src/protocols/openai-chat.ts b/packages/llm/src/protocols/openai-chat.ts index 470a1473c4..6a85c37d59 100644 --- a/packages/llm/src/protocols/openai-chat.ts +++ b/packages/llm/src/protocols/openai-chat.ts @@ -2,7 +2,6 @@ import { Array as Arr, Effect, Schema } from "effect" import { Route } from "../route/client" import { Auth } from "../route/auth" import { Endpoint } from "../route/endpoint" -import { Framing } from "../route/framing" import { HttpTransport } from "../route/transport" import { Protocol } from "../route/protocol" import { @@ -128,6 +127,7 @@ type OpenAIChatToolCallDelta = Schema.Schema.Type let lifecycle = state.lifecycle + if (delta?.reasoning_content) + lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", delta.reasoning_content) + if (delta?.content) lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.content) for (const tool of toolDeltas) { @@ -393,28 +396,15 @@ export const protocol = Protocol.make({ }, }) -const encodeBody = Schema.encodeSync(Schema.fromJsonString(OpenAIChatBody)) - -export const httpTransport = HttpTransport.httpJson({ - endpoint: Endpoint.path(PATH), - auth: Auth.bearer(), - framing: Framing.sse, - encodeBody, -}) +export const httpTransport = HttpTransport.sseJson.with() export const route = Route.make({ id: ADAPTER, provider: "openai", protocol, + endpoint: Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL }), + auth: Auth.none, transport: httpTransport, - defaults: { - baseURL: DEFAULT_BASE_URL, - }, }) -// ============================================================================= -// Model Helper -// ============================================================================= -export const model = route.model - export * as OpenAIChat from "./openai-chat" diff --git a/packages/llm/src/protocols/openai-compatible-chat.ts b/packages/llm/src/protocols/openai-compatible-chat.ts index 76deeac451..ce3f0a83d7 100644 --- a/packages/llm/src/protocols/openai-compatible-chat.ts +++ b/packages/llm/src/protocols/openai-compatible-chat.ts @@ -5,16 +5,14 @@ import * as OpenAIChat from "./openai-chat" const ADAPTER = "openai-compatible-chat" -export type OpenAICompatibleChatModelInput = Omit & { - readonly baseURL: string -} +export type OpenAICompatibleChatModelInput = RouteRoutedModelInput /** * Route for non-OpenAI providers that expose an OpenAI Chat-compatible * `/chat/completions` endpoint. Reuses `OpenAIChat.protocol` end-to-end and * overrides only the route id so providers can be resolved per-family without - * colliding with native OpenAI. The model carries the host on `baseURL`, - * supplied by whichever profile/provider helper builds it. + * colliding with native OpenAI. Provider helpers configure the route endpoint + * before model selection. */ export const route = Route.make({ id: ADAPTER, @@ -23,6 +21,4 @@ export const route = Route.make({ framing: Framing.sse, }) -export const model = Route.model(route) - export * as OpenAICompatibleChat from "./openai-compatible-chat" diff --git a/packages/llm/src/protocols/openai-responses.ts b/packages/llm/src/protocols/openai-responses.ts index 7cf734f027..88c65d187c 100644 --- a/packages/llm/src/protocols/openai-responses.ts +++ b/packages/llm/src/protocols/openai-responses.ts @@ -2,7 +2,6 @@ import { Effect, Schema } from "effect" import { Route } from "../route/client" import { Auth } from "../route/auth" import { Endpoint } from "../route/endpoint" -import { Framing } from "../route/framing" import { HttpTransport, WebSocketTransport } from "../route/transport" import { Protocol } from "../route/protocol" import { @@ -11,9 +10,12 @@ import { type FinishReason, type LLMRequest, type ProviderMetadata, + type ReasoningPart, type TextPart, type ToolCallPart, type ToolDefinition, + type ToolResultContentPart, + type ToolResultPart, } from "../schema" import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared" import { OpenAIOptions } from "./utils/openai-options" @@ -31,16 +33,45 @@ const OpenAIResponsesInputText = Schema.Struct({ type: Schema.tag("input_text"), text: Schema.String, }) +const OpenAIResponsesInputImage = Schema.Struct({ + type: Schema.tag("input_image"), + image_url: Schema.String, +}) +const OpenAIResponsesInputContent = Schema.Union([OpenAIResponsesInputText, OpenAIResponsesInputImage]) +type OpenAIResponsesInputContent = Schema.Schema.Type const OpenAIResponsesOutputText = Schema.Struct({ type: Schema.tag("output_text"), text: Schema.String, }) +const OpenAIResponsesReasoningSummaryText = Schema.Struct({ + type: Schema.tag("summary_text"), + text: Schema.String, +}) + +const OpenAIResponsesReasoningItem = Schema.Struct({ + type: Schema.tag("reasoning"), + id: Schema.String, + summary: Schema.Array(OpenAIResponsesReasoningSummaryText), + encrypted_content: optionalNull(Schema.String), +}) + +// `function_call_output.output` accepts either a plain string or an ordered +// array of content items so tools can return images in addition to text. +// https://platform.openai.com/docs/api-reference/responses/object +const OpenAIResponsesFunctionCallOutputContent = Schema.Union([OpenAIResponsesInputText, OpenAIResponsesInputImage]) + +const OpenAIResponsesFunctionCallOutput = Schema.Union([ + Schema.String, + Schema.Array(OpenAIResponsesFunctionCallOutputContent), +]) + const OpenAIResponsesInputItem = Schema.Union([ Schema.Struct({ role: Schema.tag("system"), content: Schema.String }), - Schema.Struct({ role: Schema.tag("user"), content: Schema.Array(OpenAIResponsesInputText) }), + Schema.Struct({ role: Schema.tag("user"), content: Schema.Array(OpenAIResponsesInputContent) }), Schema.Struct({ role: Schema.tag("assistant"), content: Schema.Array(OpenAIResponsesOutputText) }), + OpenAIResponsesReasoningItem, Schema.Struct({ type: Schema.tag("function_call"), call_id: Schema.String, @@ -50,7 +81,7 @@ const OpenAIResponsesInputItem = Schema.Union([ Schema.Struct({ type: Schema.tag("function_call_output"), call_id: Schema.String, - output: Schema.String, + output: OpenAIResponsesFunctionCallOutput, }), ]) type OpenAIResponsesInputItem = Schema.Schema.Type @@ -76,6 +107,7 @@ const OpenAIResponsesToolChoice = Schema.Union([ const OpenAIResponsesCoreFields = { model: Schema.String, input: Schema.Array(OpenAIResponsesInputItem), + instructions: Schema.optional(Schema.String), tools: optionalArray(OpenAIResponsesTool), tool_choice: Schema.optional(OpenAIResponsesToolChoice), store: Schema.optional(Schema.Boolean), @@ -142,24 +174,41 @@ const OpenAIResponsesStreamItem = Schema.Struct({ server_label: Schema.optional(Schema.String), output: Schema.optional(Schema.Unknown), error: Schema.optional(Schema.Unknown), + encrypted_content: optionalNull(Schema.String), }) type OpenAIResponsesStreamItem = Schema.Schema.Type +// OpenAI Responses surfaces provider failures in two related shapes. The +// streaming `error` event carries the details at the top level +// (`{ type: "error", code, message, param, sequence_number }`), while +// `response.failed` carries them under `response.error`. We capture both so +// the parser can surface a useful provider-error message in either path. +const OpenAIResponsesErrorPayload = Schema.Struct({ + code: optionalNull(Schema.String), + message: optionalNull(Schema.String), + param: optionalNull(Schema.String), +}) + const OpenAIResponsesEvent = Schema.Struct({ type: Schema.String, delta: Schema.optional(Schema.String), item_id: Schema.optional(Schema.String), item: Schema.optional(OpenAIResponsesStreamItem), response: Schema.optional( - Schema.Struct({ - id: Schema.optional(Schema.String), - service_tier: Schema.optional(Schema.String), - incomplete_details: optionalNull(Schema.Struct({ reason: Schema.String })), - usage: optionalNull(OpenAIResponsesUsage), - }), + Schema.StructWithRest( + Schema.Struct({ + id: Schema.optional(Schema.String), + service_tier: optionalNull(Schema.String), + incomplete_details: optionalNull(Schema.Struct({ reason: Schema.String })), + usage: optionalNull(OpenAIResponsesUsage), + error: optionalNull(OpenAIResponsesErrorPayload), + }), + [Schema.Record(Schema.String, Schema.Unknown)], + ), ), code: Schema.optional(Schema.String), message: Schema.optional(Schema.String), + param: Schema.optional(Schema.String), }) type OpenAIResponsesEvent = Schema.Schema.Type @@ -196,46 +245,110 @@ const lowerToolCall = (part: ToolCallPart): OpenAIResponsesInputItem => ({ arguments: ProviderShared.encodeJson(part.input), }) +const lowerReasoning = (part: ReasoningPart, store: boolean | undefined): OpenAIResponsesInputItem | undefined => { + const openai = part.providerMetadata?.openai + if (!ProviderShared.isRecord(openai) || typeof openai.itemId !== "string") return undefined + // With store:false, OpenAI only accepts previous reasoning items when the + // encrypted state is present. Bare rs_* ids point to non-persisted items. + if (store === false && typeof openai.reasoningEncryptedContent !== "string") return undefined + return { + type: "reasoning", + id: openai.itemId, + summary: part.text.length > 0 ? [{ type: "summary_text", text: part.text }] : [], + encrypted_content: + typeof openai.reasoningEncryptedContent === "string" + ? openai.reasoningEncryptedContent + : openai.reasoningEncryptedContent === null + ? null + : undefined, + } +} + +const lowerUserContent = Effect.fn("OpenAIResponses.lowerUserContent")(function* ( + part: LLMRequest["messages"][number]["content"][number], +) { + if (part.type === "text") return { type: "input_text" as const, text: part.text } + if (part.type === "media" && part.mediaType.startsWith("image/")) { + return { type: "input_image" as const, image_url: ProviderShared.mediaDataUrl(part) } + } + if (part.type === "media") return yield* invalid("OpenAI Responses user media content only supports images") + return yield* ProviderShared.unsupportedContent("OpenAI Responses", "user", ["text", "media"]) +}) + +// Tool results may carry structured text/images. Keep media as provider-native +// content instead of JSON-stringifying base64 into a prompt string. +const lowerToolResultContentItem = Effect.fn("OpenAIResponses.lowerToolResultContentItem")(function* ( + item: ToolResultContentPart, +) { + if (item.type === "text") return { type: "input_text" as const, text: item.text } + if (item.mediaType.startsWith("image/")) + return { + type: "input_image" as const, + image_url: ProviderShared.mediaDataUrl(item), + } + return yield* invalid(`OpenAI Responses tool-result media content only supports images, got ${item.mediaType}`) +}) + +const lowerToolResultOutput = Effect.fn("OpenAIResponses.lowerToolResultOutput")(function* (part: ToolResultPart) { + // Text/json/error results are encoded as a plain string for backward + // compatibility with existing cassettes and provider expectations. + if (part.result.type !== "content") return ProviderShared.toolResultText(part) + return yield* Effect.forEach(part.result.value, lowerToolResultContentItem) +}) + const lowerMessages = Effect.fn("OpenAIResponses.lowerMessages")(function* (request: LLMRequest) { const system: OpenAIResponsesInputItem[] = request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }] const input: OpenAIResponsesInputItem[] = [...system] + const store = OpenAIOptions.store(request) for (const message of request.messages) { if (message.role === "user") { - const content: TextPart[] = [] - for (const part of message.content) { - if (!ProviderShared.supportsContent(part, ["text"])) - return yield* ProviderShared.unsupportedContent("OpenAI Responses", "user", ["text"]) - content.push(part) - } - input.push({ role: "user", content: content.map((part) => ({ type: "input_text", text: part.text })) }) + input.push({ role: "user", content: yield* Effect.forEach(message.content, lowerUserContent) }) continue } if (message.role === "assistant") { const content: TextPart[] = [] + const flushText = () => { + if (content.length === 0) return + input.push({ role: "assistant", content: content.map((part) => ({ type: "output_text", text: part.text })) }) + content.splice(0, content.length) + } for (const part of message.content) { - if (!ProviderShared.supportsContent(part, ["text", "tool-call"])) - return yield* ProviderShared.unsupportedContent("OpenAI Responses", "assistant", ["text", "tool-call"]) if (part.type === "text") { content.push(part) continue } + if (part.type === "reasoning") { + flushText() + const reasoning = lowerReasoning(part, store) + if (reasoning) input.push(reasoning) + continue + } if (part.type === "tool-call") { + flushText() input.push(lowerToolCall(part)) continue } + return yield* ProviderShared.unsupportedContent("OpenAI Responses", "assistant", [ + "text", + "reasoning", + "tool-call", + ]) } - if (content.length > 0) - input.push({ role: "assistant", content: content.map((part) => ({ type: "output_text", text: part.text })) }) + flushText() continue } for (const part of message.content) { if (!ProviderShared.supportsContent(part, ["tool-result"])) return yield* ProviderShared.unsupportedContent("OpenAI Responses", "tool", ["tool-result"]) - input.push({ type: "function_call_output", call_id: part.id, output: ProviderShared.toolResultText(part) }) + input.push({ + type: "function_call_output", + call_id: part.id, + output: yield* lowerToolResultOutput(part), + }) } } @@ -251,7 +364,9 @@ const lowerOptions = Effect.fn("OpenAIResponses.lowerOptions")(function* (reques const summary = OpenAIOptions.reasoningSummary(request) const encryptedState = OpenAIOptions.encryptedReasoning(request) const verbosity = OpenAIOptions.textVerbosity(request) + const instructions = OpenAIOptions.instructions(request) return { + ...(instructions ? { instructions } : {}), ...(store !== undefined ? { store } : {}), ...(promptCacheKey ? { prompt_cache_key: promptCacheKey } : {}), ...(encryptedState ? { include: ["reasoning.encrypted_content"] as const } : {}), @@ -345,6 +460,11 @@ const isHostedToolItem = ( ): item is OpenAIResponsesStreamItem & { type: HostedToolType; id: string } => item.type in HOSTED_TOOLS && typeof item.id === "string" && item.id.length > 0 +const isReasoningItem = ( + item: OpenAIResponsesStreamItem, +): item is OpenAIResponsesStreamItem & { type: "reasoning"; id: string } => + item.type === "reasoning" && typeof item.id === "string" && item.id.length > 0 + // Round-trip the full item as the structured result so consumers can extract // outputs / sources / status without re-decoding. const hostedToolResult = (item: OpenAIResponsesStreamItem) => { @@ -394,6 +514,25 @@ const onOutputTextDelta = (state: ParserState, event: OpenAIResponsesEvent): Ste ] } +const onReasoningDelta = (state: ParserState, event: OpenAIResponsesEvent): StepResult => { + if (!event.delta) return [state, NO_EVENTS] + const events: LLMEvent[] = [] + return [ + { + ...state, + lifecycle: Lifecycle.reasoningDelta(state.lifecycle, events, event.item_id ?? "reasoning-0", event.delta), + }, + events, + ] +} + +// The summary done event does not carry encrypted continuation state. Finish the +// common reasoning block when the full reasoning item arrives in output_item.done. +const onReasoningDone = (state: ParserState, _event: OpenAIResponsesEvent): StepResult => [state, NO_EVENTS] + +const reasoningMetadata = (item: OpenAIResponsesStreamItem & { id: string }) => + openaiMetadata({ itemId: item.id, reasoningEncryptedContent: item.encrypted_content ?? null }) + const onOutputItemAdded = (state: ParserState, event: OpenAIResponsesEvent): StepResult => { const item = event.item if (item?.type !== "function_call" || !item.id) return [state, NO_EVENTS] @@ -473,6 +612,21 @@ const onOutputItemDone = Effect.fn("OpenAIResponses.onOutputItemDone")(function* return [{ ...state, lifecycle }, events] satisfies StepResult } + if (isReasoningItem(item)) { + const events: LLMEvent[] = [] + const providerMetadata = reasoningMetadata(item) + if (!state.lifecycle.reasoning.has(item.id)) { + const lifecycle = Lifecycle.stepStart(state.lifecycle, events) + events.push(LLMEvent.reasoningStart({ id: item.id, providerMetadata })) + events.push(LLMEvent.reasoningEnd({ id: item.id, providerMetadata })) + return [{ ...state, lifecycle }, events] satisfies StepResult + } + return [ + { ...state, lifecycle: Lifecycle.reasoningEnd(state.lifecycle, events, item.id, providerMetadata) }, + events, + ] satisfies StepResult + } + return [state, NO_EVENTS] satisfies StepResult }) @@ -492,18 +646,43 @@ const onResponseFinish = (state: ParserState, event: OpenAIResponsesEvent): Step return [{ ...state, lifecycle }, events] } +// Build a single human-readable message from whatever the provider supplied. +// When both code and message are present, prefix the code so consumers see +// the failure mode (e.g. `rate_limit_exceeded: Slow down`) instead of just +// the bare message — production rate limits and context-length failures used +// to be indistinguishable from generic stream drops. +const providerErrorMessage = (event: OpenAIResponsesEvent, fallback: string): string => { + const nested = event.response?.error ?? undefined + const message = event.message || nested?.message || undefined + const code = event.code || nested?.code || undefined + if (message && code) return `${code}: ${message}` + return message || code || fallback +} + const onResponseFailed = (state: ParserState, event: OpenAIResponsesEvent): StepResult => [ state, - [LLMEvent.providerError({ message: event.message ?? event.code ?? "OpenAI Responses response failed" })], + [LLMEvent.providerError({ message: providerErrorMessage(event, "OpenAI Responses response failed") })], ] const onError = (state: ParserState, event: OpenAIResponsesEvent): StepResult => [ state, - [LLMEvent.providerError({ message: event.message ?? event.code ?? "OpenAI Responses stream error" })], + [LLMEvent.providerError({ message: providerErrorMessage(event, "OpenAI Responses stream error") })], ] const step = (state: ParserState, event: OpenAIResponsesEvent) => { if (event.type === "response.output_text.delta") return Effect.succeed(onOutputTextDelta(state, event)) + if ( + event.type === "response.reasoning_text.delta" || + event.type === "response.reasoning_summary.delta" || + event.type === "response.reasoning_summary_text.delta" + ) + return Effect.succeed(onReasoningDelta(state, event)) + if ( + event.type === "response.reasoning_text.done" || + event.type === "response.reasoning_summary.done" || + event.type === "response.reasoning_summary_text.done" + ) + return Effect.succeed(onReasoningDone(state, event)) if (event.type === "response.output_item.added") return Effect.succeed(onOutputItemAdded(state, event)) if (event.type === "response.function_call_arguments.delta") return onFunctionCallArgumentsDelta(state, event) if (event.type === "response.output_item.done") return onOutputItemDone(state, event) @@ -536,27 +715,18 @@ export const protocol = Protocol.make({ }, }) -const encodeBody = Schema.encodeSync(Schema.fromJsonString(OpenAIResponsesBody)) -const transportBase = { - endpoint: Endpoint.path(PATH), - auth: Auth.bearer(), - encodeBody, -} -const routeDefaults = { - baseURL: DEFAULT_BASE_URL, -} +const endpoint = Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL }) +const auth = Auth.none -export const httpTransport = HttpTransport.httpJson({ - ...transportBase, - framing: Framing.sse, -}) +export const httpTransport = HttpTransport.sseJson.with() export const route = Route.make({ id: ADAPTER, provider: "openai", protocol, + endpoint, + auth, transport: httpTransport, - defaults: routeDefaults, }) const decodeWebSocketMessage = ProviderShared.validateWith(Schema.decodeUnknownEffect(OpenAIResponsesWebSocketMessage)) @@ -569,8 +739,10 @@ const webSocketMessage = (body: OpenAIResponsesBody | Record) = return yield* decodeWebSocketMessage({ ...message, type: "response.create" }) }) -export const webSocketTransport = WebSocketTransport.json({ - ...transportBase, +export const webSocketTransport = WebSocketTransport.jsonTransport.with< + OpenAIResponsesBody, + OpenAIResponsesWebSocketMessage +>({ toMessage: webSocketMessage, encodeMessage: encodeWebSocketMessage, }) @@ -579,15 +751,9 @@ export const webSocketRoute = Route.make({ id: `${ADAPTER}-websocket`, provider: "openai", protocol, + endpoint, + auth, transport: webSocketTransport, - defaults: routeDefaults, }) -// ============================================================================= -// Model Helper -// ============================================================================= -export const model = route.model - -export const webSocketModel = webSocketRoute.model - export * as OpenAIResponses from "./openai-responses" diff --git a/packages/llm/src/protocols/shared.ts b/packages/llm/src/protocols/shared.ts index b8067bbe90..aa37c62e43 100644 --- a/packages/llm/src/protocols/shared.ts +++ b/packages/llm/src/protocols/shared.ts @@ -11,6 +11,7 @@ import { type MediaPart, type ToolResultPart, } from "../schema" +export { isRecord } from "../utils/record" export const Json = Schema.fromJsonString(Schema.Unknown) export const decodeJson = Schema.decodeUnknownSync(Json) @@ -19,13 +20,6 @@ export const JsonObject = Schema.Record(Schema.String, Schema.Unknown) export const optionalArray = (schema: S) => Schema.optional(Schema.Array(schema)) export const optionalNull = (schema: S) => Schema.optional(Schema.NullOr(schema)) -/** - * Plain-record narrowing. Excludes arrays so routes checking nested JSON - * Schema fragments don't accidentally treat a tuple as a key/value bag. - */ -export const isRecord = (value: unknown): value is Record => - typeof value === "object" && value !== null && !Array.isArray(value) - /** * Streaming tool-call accumulator. Adapters that build a tool call across * multiple `tool-input-delta` chunks store the partial JSON input string here @@ -86,7 +80,7 @@ export const subtractTokens = (total: number | undefined, subtrahend: number | u */ export const sumTokens = (...values: ReadonlyArray): number | undefined => { if (values.every((value) => value === undefined)) return undefined - return values.reduce((acc, value) => acc + (value ?? 0), 0) + return values.reduce((acc: number, value) => acc + (value ?? 0), 0) } export const eventError = (route: string, message: string, raw?: string) => @@ -128,10 +122,21 @@ export const parseToolInput = (route: string, name: string, raw: string) => export const mediaBytes = (part: MediaPart) => typeof part.data === "string" ? part.data : Buffer.from(part.data).toString("base64") +export const mediaBase64 = (part: MediaPart) => { + if (typeof part.data !== "string" || !part.data.startsWith("data:")) return mediaBytes(part) + return part.data.slice(part.data.indexOf(",") + 1) +} + +export const mediaDataUrl = (part: MediaPart) => + typeof part.data === "string" && part.data.startsWith("data:") + ? part.data + : `data:${part.mediaType};base64,${mediaBytes(part)}` + export const trimBaseUrl = (value: string) => value.replace(/\/+$/, "") export const toolResultText = (part: ToolResultPart) => { if (part.result.type === "text" || part.result.type === "error") return String(part.result.value) + if (part.result.type === "content") return encodeJson(part.result.value) return encodeJson(part.result.value) } diff --git a/packages/llm/src/protocols/utils/bedrock-auth.ts b/packages/llm/src/protocols/utils/bedrock-auth.ts index 58d16d95f8..37cc451256 100644 --- a/packages/llm/src/protocols/utils/bedrock-auth.ts +++ b/packages/llm/src/protocols/utils/bedrock-auth.ts @@ -1,15 +1,14 @@ import { AwsV4Signer } from "aws4fetch" -import { Effect, Option, Schema } from "effect" +import { Effect } from "effect" import { Headers } from "effect/unstable/http" import { Auth, type AuthInput } from "../../route/auth" -import type { LLMRequest } from "../../schema" import { ProviderShared } from "../shared" /** - * AWS credentials for SigV4 signing. Bedrock also supports Bearer API key auth - * via `model.apiKey`, which bypasses SigV4 signing. STS-vended credentials - * should be refreshed by the consumer (rebuild the model) before they expire; - * the route does not refresh. + * AWS credentials for SigV4 signing. Bedrock also supports Bearer API key auth, + * which provider facades configure as route auth instead of SigV4. STS-vended + * credentials should be refreshed by the consumer (rebuild the model) before + * they expire; the route does not refresh. */ export interface Credentials { readonly region: string @@ -18,32 +17,6 @@ export interface Credentials { readonly sessionToken?: string } -const NativeCredentials = Schema.Struct({ - accessKeyId: Schema.String, - secretAccessKey: Schema.String, - region: Schema.optional(Schema.String), - sessionToken: Schema.optional(Schema.String), -}) - -const decodeNativeCredentials = Schema.decodeUnknownOption(NativeCredentials) - -export const region = (request: LLMRequest) => { - const fromNative = request.model.native?.aws_region - if (typeof fromNative === "string" && fromNative !== "") return fromNative - return ( - decodeNativeCredentials(request.model.native?.aws_credentials).pipe( - Option.map((credentials) => credentials.region), - Option.getOrUndefined, - ) ?? "us-east-1" - ) -} - -const credentialsFromInput = (request: LLMRequest): Credentials | undefined => - decodeNativeCredentials(request.model.native?.aws_credentials).pipe( - Option.map((creds) => ({ ...creds, region: creds.region ?? region(request) })), - Option.getOrUndefined, - ) - const signRequest = (input: { readonly url: string readonly body: string @@ -71,33 +44,27 @@ const signRequest = (input: { ), }) -/** - * Bedrock auth. `model.apiKey` (Bedrock's newer Bearer API key auth) wins if - * set; otherwise sign the exact JSON bytes with SigV4 using credentials from - * `model.native.aws_credentials`. - */ -export const auth = Auth.custom((input: AuthInput) => { - if (input.request.model.apiKey) return Auth.toEffect(Auth.bearer())(input) - return Effect.gen(function* () { - const credentials = credentialsFromInput(input.request) - if (!credentials) { - return yield* ProviderShared.invalidRequest( - "Bedrock Converse requires either model.apiKey or AWS credentials in model.native.aws_credentials", - ) - } - const headersForSigning = Headers.set(input.headers, "content-type", "application/json") - const signed = yield* signRequest({ url: input.url, body: input.body, headers: headersForSigning, credentials }) - return Headers.setAll(headersForSigning, signed) - }) -}) - -export const nativeCredentials = (native: Record | undefined, credentials: Credentials | undefined) => - credentials - ? { - ...native, - aws_credentials: credentials, - aws_region: credentials.region, +/** Sign the exact JSON bytes with SigV4 using credentials configured on the route. */ +export const sigV4 = (credentials: Credentials | undefined) => + Auth.custom((input: AuthInput) => { + return Effect.gen(function* () { + if (!credentials) { + return yield* ProviderShared.invalidRequest( + "Bedrock Converse requires either route bearer auth or AWS credentials configured on the route", + ) } - : native + const headersForSigning = Headers.set(input.headers, "content-type", "application/json") + const signed = yield* signRequest({ + url: input.url, + body: input.body, + headers: headersForSigning, + credentials, + }) + return Headers.setAll(headersForSigning, signed) + }) + }) + +/** Bedrock route auth defaults to SigV4 and expects credentials from route configuration. */ +export const auth = sigV4(undefined) export * as BedrockAuth from "./bedrock-auth" diff --git a/packages/llm/src/protocols/utils/openai-options.ts b/packages/llm/src/protocols/utils/openai-options.ts index 080ef83f50..59e201421d 100644 --- a/packages/llm/src/protocols/utils/openai-options.ts +++ b/packages/llm/src/protocols/utils/openai-options.ts @@ -52,4 +52,9 @@ export const textVerbosity = (request: LLMRequest) => { return isTextVerbosity(value) ? value : undefined } +export const instructions = (request: LLMRequest) => { + const value = options(request)?.instructions + return typeof value === "string" ? value : undefined +} + export * as OpenAIOptions from "./openai-options" diff --git a/packages/llm/src/provider.ts b/packages/llm/src/provider.ts index 8299b5865c..7f69583418 100644 --- a/packages/llm/src/provider.ts +++ b/packages/llm/src/provider.ts @@ -1,14 +1,20 @@ -import type { RouteModelInput } from "./route/client" -import type { ModelID, ModelRef, ProviderID } from "./schema" +import type { RouteDefaultsInput } from "./route/client" +import type { Model, ModelID, ProviderID } from "./schema" -export type ModelOptions = Omit +export type ModelOptions = RouteDefaultsInput +/** + * Advanced structural provider definition helper. Built-in providers should + * prefer explicit `configure(options).model(id)` facades so deployment config is + * chosen before model selection. The optional `apis` map remains for external + * structural providers that expose multiple route selectors behind one provider. + */ export type ModelFactory = ( id: string | ModelID, options?: Options, -) => ModelRef +) => Model -type AnyModelFactory = (...args: never[]) => ModelRef +type AnyModelFactory = (...args: never[]) => Model export interface Definition { readonly id: ProviderID @@ -18,8 +24,8 @@ export interface Definition { type DefinitionShape = { readonly id: ProviderID - readonly model: (...args: never[]) => ModelRef - readonly apis?: Record ModelRef> + readonly model: (...args: never[]) => Model + readonly apis?: Record Model> } type NoExtraFields = Input & Record, never> diff --git a/packages/llm/src/providers/amazon-bedrock.ts b/packages/llm/src/providers/amazon-bedrock.ts index 82408d514e..2f1791e0d6 100644 --- a/packages/llm/src/providers/amazon-bedrock.ts +++ b/packages/llm/src/providers/amazon-bedrock.ts @@ -1,12 +1,12 @@ -import { Route, type RouteModelInput } from "../route/client" -import { Provider } from "../provider" +import type { RouteDefaultsInput } from "../route/client" +import { Auth } from "../route/auth" import { ProviderID, type ModelID } from "../schema" import * as BedrockConverse from "../protocols/bedrock-converse" import type { BedrockCredentials } from "../protocols/bedrock-converse" export const id = ProviderID.make("amazon-bedrock") -export type ModelOptions = Omit & { +export type Config = RouteDefaultsInput & { readonly apiKey?: string readonly headers?: Record readonly credentials?: BedrockCredentials @@ -15,34 +15,29 @@ export type ModelOptions = Omit & { /** Override the computed `https://bedrock-runtime..amazonaws.com` URL. */ readonly baseURL?: string } -type ModelInput = ModelOptions & Pick - export const routes = [BedrockConverse.route] const bedrockBaseURL = (region: string) => `https://bedrock-runtime.${region}.amazonaws.com` -const converseModel = Route.model( - BedrockConverse.route, - { - provider: "amazon-bedrock", - }, - { - mapInput: (input) => { - const { credentials, region, baseURL, ...rest } = input - const resolvedRegion = region ?? credentials?.region ?? "us-east-1" - return { - ...rest, - baseURL: baseURL ?? bedrockBaseURL(resolvedRegion), - native: BedrockConverse.nativeCredentials(input.native, credentials), - } - }, - }, -) +const configuredRoute = (input: Config) => { + const { apiKey, credentials, region, baseURL, ...rest } = input + const resolvedRegion = region ?? credentials?.region ?? "us-east-1" + return BedrockConverse.route.with({ + ...rest, + provider: id, + endpoint: { baseURL: baseURL ?? bedrockBaseURL(resolvedRegion) }, + auth: apiKey === undefined ? BedrockConverse.sigV4Auth(credentials) : Auth.bearer(apiKey), + }) +} -export const model = (modelID: string | ModelID, options: ModelOptions = {}) => - converseModel({ ...options, id: modelID }) +export const configure = (input: Config = {}) => { + const route = configuredRoute(input) + return { + id, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure, + } +} -export const provider = Provider.make({ - id, - model, -}) +export const provider = configure() +export const model = provider.model diff --git a/packages/llm/src/providers/anthropic.ts b/packages/llm/src/providers/anthropic.ts index cca12bf7c2..0c9640af5e 100644 --- a/packages/llm/src/providers/anthropic.ts +++ b/packages/llm/src/providers/anthropic.ts @@ -1,5 +1,6 @@ -import type { RouteModelInput } from "../route/client" -import { Provider } from "../provider" +import type { RouteDefaultsInput } from "../route/client" +import { Auth } from "../route/auth" +import type { ProviderAuthOption } from "../route/auth-options" import { ProviderID, type ModelID } from "../schema" import * as AnthropicMessages from "../protocols/anthropic-messages" @@ -7,12 +8,28 @@ export const id = ProviderID.make("anthropic") export const routes = [AnthropicMessages.route] -export const model = ( - id: string | ModelID, - options: Omit & { readonly baseURL?: string } = {}, -) => AnthropicMessages.model({ ...options, id }) +export type Config = RouteDefaultsInput & ProviderAuthOption<"optional"> & { readonly baseURL?: string } -export const provider = Provider.make({ - id, - model, -}) +const auth = (options: ProviderAuthOption<"optional">) => { + if ("auth" in options && options.auth) return options.auth + return Auth.optional("apiKey" in options ? options.apiKey : undefined, "apiKey") + .orElse(Auth.config("ANTHROPIC_API_KEY")) + .pipe(Auth.header("x-api-key")) +} + +const configuredRoute = (input: Config) => { + const { apiKey: _, auth: _auth, baseURL, ...rest } = input + return AnthropicMessages.route.with({ ...rest, endpoint: { baseURL }, auth: auth(input) }) +} + +export const configure = (input: Config = {}) => { + const route = configuredRoute(input) + return { + id, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure, + } +} + +export const provider = configure() +export const model = provider.model diff --git a/packages/llm/src/providers/azure.ts b/packages/llm/src/providers/azure.ts index 8d60fb6669..bfac2d1cad 100644 --- a/packages/llm/src/providers/azure.ts +++ b/packages/llm/src/providers/azure.ts @@ -1,83 +1,110 @@ import { Auth } from "../route/auth" import { type AtLeastOne, type ProviderAuthOption } from "../route/auth-options" -import { Route } from "../route/client" -import type { ModelInput } from "../llm" -import { Provider } from "../provider" +import type { Route as RouteDef, RouteDefaultsInput } from "../route/client" import { ProviderID, type ModelID } from "../schema" import * as OpenAIChat from "../protocols/openai-chat" import * as OpenAIResponses from "../protocols/openai-responses" import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options" export const id = ProviderID.make("azure") -const routeAuth = Auth.remove("authorization").andThen(Auth.apiKeyHeader("api-key")) +const routeAuth = Auth.remove("authorization") // Azure needs the customer's resource URL; supply either `resourceName` // (helper builds the URL) or `baseURL` directly. type AzureURL = AtLeastOne<{ readonly resourceName: string; readonly baseURL: string }> export type ModelOptions = AzureURL & - Omit & + RouteDefaultsInput & ProviderAuthOption<"optional"> & { readonly apiVersion?: string + readonly queryParams?: Record readonly useCompletionUrls?: boolean readonly providerOptions?: OpenAIProviderOptionsInput } -type AzureModelInput = ModelOptions & Pick +export type Config = ModelOptions const resourceBaseURL = (resourceName: string) => `https://${resourceName.trim()}.openai.azure.com/openai/v1` const responsesRoute = OpenAIResponses.route.with({ id: "azure-openai-responses", provider: id, - transport: OpenAIResponses.httpTransport.with({ auth: routeAuth }), + auth: routeAuth, + endpoint: { + query: { "api-version": "v1" }, + }, }) const chatRoute = OpenAIChat.route.with({ id: "azure-openai-chat", provider: id, - transport: OpenAIChat.httpTransport.with({ auth: routeAuth }), + auth: routeAuth, + endpoint: { + query: { "api-version": "v1" }, + }, }) export const routes = [responsesRoute, chatRoute] -const mapInput = (input: AzureModelInput) => { - const { apiKey: _, apiVersion, resourceName, useCompletionUrls, ...rest } = input - return { - ...withOpenAIOptions(input.id, rest), - auth: - "auth" in input && input.auth - ? input.auth - : Auth.remove("authorization").andThen( - Auth.optional("apiKey" in input ? input.apiKey : undefined, "apiKey") - .orElse(Auth.config("AZURE_OPENAI_API_KEY")) - .pipe(Auth.header("api-key")), - ), - // AtLeastOne guarantees at least one is set; baseURL wins if both are. - baseURL: rest.baseURL ?? resourceBaseURL(resourceName!), - queryParams: { - ...rest.queryParams, - "api-version": apiVersion ?? rest.queryParams?.["api-version"] ?? "v1", +const defaults = (input: Config) => { + const { + apiKey: _, + apiVersion: _apiVersion, + resourceName: _resourceName, + useCompletionUrls: _useCompletionUrls, + baseURL: _baseURL, + queryParams: _queryParams, + ...rest + } = input + if ("auth" in rest) { + const { auth: _, ...withoutAuth } = rest + return withoutAuth + } + return rest +} + +const auth = (input: Config) => { + if ("auth" in input && input.auth) return input.auth + return Auth.remove("authorization").andThen( + Auth.optional("apiKey" in input ? input.apiKey : undefined, "apiKey") + .orElse(Auth.config("AZURE_OPENAI_API_KEY")) + .pipe(Auth.header("api-key")), + ) +} + +const configuredRoute = (route: RouteDef, input: Config) => + route.with({ + auth: auth(input), + endpoint: { + // AtLeastOne guarantees at least one is set; baseURL wins if both are. + baseURL: input.baseURL ?? resourceBaseURL(input.resourceName!), + query: { + ...(input.apiVersion ? { "api-version": input.apiVersion } : {}), + ...input.queryParams, + }, }, + }) + +export const configure = (input: Config) => { + const configuredResponsesRoute = configuredRoute(responsesRoute, input) + const configuredChatRoute = configuredRoute(chatRoute, input) + const modelDefaults = defaults(input) + + const responses = (modelID: string | ModelID) => + configuredResponsesRoute.with(withOpenAIOptions(modelID, modelDefaults)).model({ id: modelID }) + + const chat = (modelID: string | ModelID) => + configuredChatRoute.with(withOpenAIOptions(modelID, modelDefaults)).model({ id: modelID }) + + return { + id, + model: (modelID: string | ModelID) => (input.useCompletionUrls === true ? chat(modelID) : responses(modelID)), + responses, + chat, + configure, } } -const chatModel = Route.model(chatRoute, {}, { mapInput }) -const responsesModel = Route.model(responsesRoute, {}, { mapInput }) - -export const responses = (modelID: string | ModelID, options: ModelOptions) => - responsesModel({ ...options, id: modelID }) - -export const chat = (modelID: string | ModelID, options: ModelOptions) => chatModel({ ...options, id: modelID }) - -export const model = (modelID: string | ModelID, options: ModelOptions) => { - if (options.useCompletionUrls === true) return chat(modelID, options) - return responses(modelID, options) -} - -export const provider = Provider.make({ +export const provider = { id, - model, - apis: { responses, chat }, -}) - -export const apis = provider.apis + configure, +} diff --git a/packages/llm/src/providers/cloudflare.ts b/packages/llm/src/providers/cloudflare.ts index 263595a755..a006152e98 100644 --- a/packages/llm/src/providers/cloudflare.ts +++ b/packages/llm/src/providers/cloudflare.ts @@ -1,19 +1,16 @@ import type { Config, Redacted } from "effect" -import { type ModelInput } from "../llm" -import { Provider } from "../provider" import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat" import { Auth } from "../route/auth" import { AuthOptions, type AtLeastOne, type ProviderAuthOption } from "../route/auth-options" -import { Route } from "../route/client" +import type { RouteDefaultsInput } from "../route/client" import { ProviderID, type ModelID } from "../schema" export const aiGatewayID = ProviderID.make("cloudflare-ai-gateway") export const workersAIID = ProviderID.make("cloudflare-workers-ai") -export const id = aiGatewayID export const aiGatewayAuthEnvVars = ["CLOUDFLARE_API_TOKEN", "CF_AIG_TOKEN"] as const export const workersAIAuthEnvVars = ["CLOUDFLARE_API_KEY", "CLOUDFLARE_WORKERS_AI_TOKEN"] as const -type CloudflareSecret = string | Redacted.Redacted | Config.Config> +type CloudflareSecret = string | Redacted.Redacted | Config.Config type GatewayURL = AtLeastOne<{ readonly accountId: string @@ -23,32 +20,26 @@ type GatewayURL = AtLeastOne<{ } export type AIGatewayOptions = GatewayURL & - Omit & + RouteDefaultsInput & ProviderAuthOption<"optional"> & { /** Cloudflare AI Gateway authentication token. Sent as `cf-aig-authorization`. */ readonly gatewayApiKey?: CloudflareSecret } -type AIGatewayInput = AIGatewayOptions & Pick - type WorkersAIURL = AtLeastOne<{ readonly accountId: string readonly baseURL: string }> -export type WorkersAIOptions = WorkersAIURL & - Omit & - ProviderAuthOption<"optional"> - -type WorkersAIInput = WorkersAIOptions & Pick +export type WorkersAIOptions = WorkersAIURL & RouteDefaultsInput & ProviderAuthOption<"optional"> export const aiGatewayBaseURL = (input: GatewayURL) => { if (input.baseURL) return input.baseURL - if (!input.accountId) throw new Error("Cloudflare.aiGateway requires accountId unless baseURL is supplied") + if (!input.accountId) throw new Error("CloudflareAIGateway.configure requires accountId unless baseURL is supplied") return `https://gateway.ai.cloudflare.com/v1/${encodeURIComponent(input.accountId)}/${encodeURIComponent(input.gatewayId?.trim() || "default")}/compat` } -const aiGatewayAuth = (input: AIGatewayInput) => { +const aiGatewayAuth = (input: AIGatewayOptions) => { if ("auth" in input && input.auth) return input.auth const gateway = Auth.optional(input.gatewayApiKey, "gatewayApiKey") .orElse(Auth.config("CLOUDFLARE_API_TOKEN")) @@ -61,11 +52,11 @@ const aiGatewayAuth = (input: AIGatewayInput) => { export const workersAIBaseURL = (input: WorkersAIURL) => { if (input.baseURL) return input.baseURL - if (!input.accountId) throw new Error("Cloudflare.workersAI requires accountId unless baseURL is supplied") + if (!input.accountId) throw new Error("CloudflareWorkersAI.configure requires accountId unless baseURL is supplied") return `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(input.accountId)}/ai/v1` } -const workersAIAuth = (input: WorkersAIInput) => { +const workersAIAuth = (input: WorkersAIOptions) => { return AuthOptions.bearer(input, workersAIAuthEnvVars) } @@ -81,59 +72,56 @@ export const workersAIRoute = OpenAICompatibleChat.route.with({ export const routes = [aiGatewayRoute, workersAIRoute] -const aiGatewayModel = Route.model( - aiGatewayRoute, - { - provider: id, - }, - { - mapInput: (input) => { - const { - accountId: _accountId, - gatewayId: _gatewayId, - apiKey: _apiKey, - gatewayApiKey: _gatewayApiKey, - auth: _auth, - ...rest - } = input - return { - ...rest, - auth: aiGatewayAuth(input), - baseURL: aiGatewayBaseURL(input), - } - }, - }, -) +const aiGatewayDefaults = (options: AIGatewayOptions) => { + const { + accountId: _accountId, + gatewayId: _gatewayId, + apiKey: _apiKey, + gatewayApiKey: _gatewayApiKey, + baseURL: _baseURL, + auth: _auth, + ...rest + } = options + return rest +} -const workersAIModel = Route.model( - workersAIRoute, - { - provider: workersAIID, - }, - { - mapInput: (input) => { - const { accountId: _accountId, apiKey: _apiKey, auth: _auth, ...rest } = input - return { - ...rest, - auth: workersAIAuth(input), - baseURL: workersAIBaseURL(input), - } - }, - }, -) +const workersAIDefaults = (options: WorkersAIOptions) => { + const { accountId: _accountId, apiKey: _apiKey, auth: _auth, baseURL: _baseURL, ...rest } = options + return rest +} -export const aiGateway = (modelID: string | ModelID, options: AIGatewayOptions) => - aiGatewayModel({ ...options, id: modelID }) +const configureAIGateway = (options: AIGatewayOptions) => { + const route = aiGatewayRoute.with({ + ...aiGatewayDefaults(options), + endpoint: { baseURL: aiGatewayBaseURL(options) }, + auth: aiGatewayAuth(options), + }) + return { + id: aiGatewayID, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure: configureAIGateway, + } +} -export const workersAI = (modelID: string | ModelID, options: WorkersAIOptions) => - workersAIModel({ ...options, id: modelID }) +const configureWorkersAI = (options: WorkersAIOptions) => { + const route = workersAIRoute.with({ + ...workersAIDefaults(options), + endpoint: { baseURL: workersAIBaseURL(options) }, + auth: workersAIAuth(options), + }) + return { + id: workersAIID, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure: configureWorkersAI, + } +} -export const model = aiGateway +export const CloudflareAIGateway = { + id: aiGatewayID, + configure: configureAIGateway, +} -export const provider = Provider.make({ - id, - model, - apis: { aiGateway, workersAI }, -}) - -export const apis = provider.apis +export const CloudflareWorkersAI = { + id: workersAIID, + configure: configureWorkersAI, +} diff --git a/packages/llm/src/providers/github-copilot.ts b/packages/llm/src/providers/github-copilot.ts index 5de738a3bf..fa6bba7422 100644 --- a/packages/llm/src/providers/github-copilot.ts +++ b/packages/llm/src/providers/github-copilot.ts @@ -1,6 +1,5 @@ -import { Route } from "../route/client" -import type { ModelInput } from "../llm" -import { Provider } from "../provider" +import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" +import type { RouteDefaultsInput } from "../route/client" import { ProviderID, type ModelID } from "../schema" import * as OpenAIChat from "../protocols/openai-chat" import * as OpenAIResponses from "../protocols/openai-responses" @@ -10,10 +9,11 @@ export const id = ProviderID.make("github-copilot") // GitHub Copilot has no canonical public URL — callers (opencode, etc.) must // supply `baseURL` explicitly. -export type ModelOptions = Omit & { - readonly providerOptions?: OpenAIProviderOptionsInput -} -type CopilotModelInput = ModelOptions & Pick +export type ModelOptions = Omit & + ProviderAuthOption<"optional"> & { + readonly baseURL: string + readonly providerOptions?: OpenAIProviderOptionsInput + } export const shouldUseResponsesApi = (modelID: string | ModelID) => { const model = String(modelID) @@ -24,25 +24,43 @@ export const shouldUseResponsesApi = (modelID: string | ModelID) => { export const routes = [OpenAIResponses.route, OpenAIChat.route] -const mapInput = (input: CopilotModelInput) => withOpenAIOptions(input.id, input) +const chatRoute = OpenAIChat.route.with({ provider: id }) +const responsesRoute = OpenAIResponses.route.with({ provider: id }) -const chatModel = Route.model(OpenAIChat.route, { provider: id }, { mapInput }) -const responsesModel = Route.model(OpenAIResponses.route, { provider: id }, { mapInput }) - -export const responses = (modelID: string | ModelID, options: ModelOptions) => - responsesModel({ ...options, id: modelID }) - -export const chat = (modelID: string | ModelID, options: ModelOptions) => chatModel({ ...options, id: modelID }) - -export const model = (modelID: string | ModelID, options: ModelOptions) => { - const create = shouldUseResponsesApi(modelID) ? responsesModel : chatModel - return create({ ...options, id: modelID }) +const defaults = (options: ModelOptions) => { + const { apiKey: _, auth: _auth, baseURL: _baseURL, ...rest } = options + return rest } -export const provider = Provider.make({ - id, - model, - apis: { responses, chat }, -}) +const configuredResponsesRoute = (options: ModelOptions) => + responsesRoute.with({ + endpoint: { baseURL: options.baseURL }, + auth: AuthOptions.bearer(options, []), + }) -export const apis = provider.apis +const configuredChatRoute = (options: ModelOptions) => + chatRoute.with({ + endpoint: { baseURL: options.baseURL }, + auth: AuthOptions.bearer(options, []), + }) + +export const configure = (options: ModelOptions) => { + const responsesRoute = configuredResponsesRoute(options) + const chatRoute = configuredChatRoute(options) + const responses = (modelID: string | ModelID) => + responsesRoute.with(withOpenAIOptions(modelID, defaults(options))).model({ id: modelID }) + const chat = (modelID: string | ModelID) => + chatRoute.with(withOpenAIOptions(modelID, defaults(options))).model({ id: modelID }) + return { + id, + model: (modelID: string | ModelID) => (shouldUseResponsesApi(modelID) ? responses(modelID) : chat(modelID)), + responses, + chat, + configure, + } +} + +export const provider = { + id, + configure, +} diff --git a/packages/llm/src/providers/google.ts b/packages/llm/src/providers/google.ts index c03b9a7c25..c8a72c31f6 100644 --- a/packages/llm/src/providers/google.ts +++ b/packages/llm/src/providers/google.ts @@ -1,5 +1,6 @@ -import type { RouteModelInput } from "../route/client" -import { Provider } from "../provider" +import type { RouteDefaultsInput } from "../route/client" +import { Auth } from "../route/auth" +import type { ProviderAuthOption } from "../route/auth-options" import { ProviderID, type ModelID } from "../schema" import * as Gemini from "../protocols/gemini" @@ -7,12 +8,28 @@ export const id = ProviderID.make("google") export const routes = [Gemini.route] -export const model = ( - id: string | ModelID, - options: Omit & { readonly baseURL?: string } = {}, -) => Gemini.model({ ...options, id }) +export type Config = RouteDefaultsInput & ProviderAuthOption<"optional"> & { readonly baseURL?: string } -export const provider = Provider.make({ - id, - model, -}) +const auth = (options: ProviderAuthOption<"optional">) => { + if ("auth" in options && options.auth) return options.auth + return Auth.optional("apiKey" in options ? options.apiKey : undefined, "apiKey") + .orElse(Auth.config("GOOGLE_GENERATIVE_AI_API_KEY")) + .pipe(Auth.header("x-goog-api-key")) +} + +const configuredRoute = (input: Config) => { + const { apiKey: _, auth: _auth, baseURL, ...rest } = input + return Gemini.route.with({ ...rest, endpoint: { baseURL }, auth: auth(input) }) +} + +export const configure = (input: Config = {}) => { + const route = configuredRoute(input) + return { + id, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure, + } +} + +export const provider = configure() +export const model = provider.model diff --git a/packages/llm/src/providers/index.ts b/packages/llm/src/providers/index.ts index 39adbe25c0..774274cf2d 100644 --- a/packages/llm/src/providers/index.ts +++ b/packages/llm/src/providers/index.ts @@ -2,6 +2,7 @@ export * as Anthropic from "./anthropic" export * as AmazonBedrock from "./amazon-bedrock" export * as Azure from "./azure" export * as Cloudflare from "./cloudflare" +export { CloudflareAIGateway, CloudflareWorkersAI } from "./cloudflare" export * as GitHubCopilot from "./github-copilot" export * as Google from "./google" export * as OpenAI from "./openai" diff --git a/packages/llm/src/providers/openai-compatible.ts b/packages/llm/src/providers/openai-compatible.ts index e37dcb4adf..a79f65f6df 100644 --- a/packages/llm/src/providers/openai-compatible.ts +++ b/packages/llm/src/providers/openai-compatible.ts @@ -1,56 +1,60 @@ -import { Provider } from "../provider" import { ProviderID, type ModelID } from "../schema" import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat" -import type { OpenAICompatibleChatModelInput } from "../protocols/openai-compatible-chat" +import type { RouteDefaultsInput } from "../route/client" +import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" import { profiles, type OpenAICompatibleProfile } from "./openai-compatible-profile" export const id = ProviderID.make("openai-compatible") -export type ModelOptions = Omit & { - readonly provider: string -} +type GenericModelOptions = RouteDefaultsInput & + ProviderAuthOption<"optional"> & { + readonly provider?: string + readonly baseURL: string + } -type GenericModelOptions = Omit & { - readonly provider?: string -} - -export type FamilyModelOptions = Omit & { - readonly baseURL?: string -} +export type FamilyModelOptions = RouteDefaultsInput & + ProviderAuthOption<"optional"> & { + readonly baseURL?: string + } export const routes = [OpenAICompatibleChat.route] -export const model = (id: string | ModelID, options: ModelOptions) => { - return OpenAICompatibleChat.model({ - ...options, - id, - provider: ProviderID.make(options.provider), +export const configure = (input: GenericModelOptions) => { + const provider = input.provider ?? "openai-compatible" + const { provider: _, baseURL, apiKey: _apiKey, auth: _auth, ...rest } = input + const route = OpenAICompatibleChat.route.with({ + ...rest, + provider, + endpoint: { baseURL }, + auth: AuthOptions.bearer(input, []), }) + return { + id: ProviderID.make(provider), + model: (modelID: string | ModelID) => route.model({ id: modelID, provider: ProviderID.make(provider) }), + configure, + } } -export const profileModel = ( - profile: OpenAICompatibleProfile, - id: string | ModelID, - options: FamilyModelOptions = {}, -) => - OpenAICompatibleChat.model({ - ...options, - id, - provider: profile.provider, - baseURL: options.baseURL ?? profile.baseURL, - }) +const define = (profile: OpenAICompatibleProfile) => { + const configureProfile = (input: FamilyModelOptions = {}) => { + const facade = configure({ + ...input, + baseURL: input.baseURL ?? profile.baseURL, + provider: profile.provider, + }) + return { + id: ProviderID.make(profile.provider), + model: facade.model, + configure: configureProfile, + } + } + return configureProfile() +} -const define = (profile: OpenAICompatibleProfile) => - Provider.make({ - id: ProviderID.make(profile.provider), - model: (id: string | ModelID, options: FamilyModelOptions = {}) => profileModel(profile, id, options), - }) - -export const provider = Provider.make({ +export const provider = { id, - model: (id: string | ModelID, options: GenericModelOptions) => - model(id, { ...options, provider: options.provider ?? "openai-compatible" }), -}) + configure, +} export const baseten = define(profiles.baseten) export const cerebras = define(profiles.cerebras) diff --git a/packages/llm/src/providers/openai-options.ts b/packages/llm/src/providers/openai-options.ts index 8d3980f609..512b94fdf7 100644 --- a/packages/llm/src/providers/openai-options.ts +++ b/packages/llm/src/providers/openai-options.ts @@ -59,10 +59,9 @@ export const withOpenAIOptions = { +): Omit & { readonly providerOptions?: ProviderOptions } => { return { ...options, - id: modelID, providerOptions: mergeProviderOptions(openAIDefaultOptions(modelID, defaults), options.providerOptions), } } diff --git a/packages/llm/src/providers/openai.ts b/packages/llm/src/providers/openai.ts index cbd9b99522..c4335f8411 100644 --- a/packages/llm/src/providers/openai.ts +++ b/packages/llm/src/providers/openai.ts @@ -1,6 +1,5 @@ import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" -import type { RouteModelInput } from "../route/client" -import { Provider } from "../provider" +import type { Route, RouteDefaultsInput } from "../route/client" import { ProviderID, type ModelID } from "../schema" import * as OpenAIChat from "../protocols/openai-chat" import * as OpenAIResponses from "../protocols/openai-responses" @@ -15,39 +14,50 @@ export const routes = [OpenAIResponses.route, OpenAIResponses.webSocketRoute, Op // This provider facade wraps the lower-level Responses and Chat model factories // with OpenAI-specific conveniences: typed options, API-key sugar, env fallback, // and default option normalization. -type OpenAIModelInput = Omit & +export type Config = RouteDefaultsInput & ProviderAuthOption<"optional"> & { readonly baseURL?: string + readonly queryParams?: Record readonly providerOptions?: OpenAIProviderOptionsInput } const auth = (options: ProviderAuthOption<"optional">) => AuthOptions.bearer(options, "OPENAI_API_KEY") -export const responses = (id: string | ModelID, options: OpenAIModelInput> = {}) => { - const { apiKey: _, ...rest } = options - return OpenAIResponses.model(withOpenAIOptions(id, { ...rest, auth: auth(options) }, { textVerbosity: true })) +const defaults = (input: Config) => { + const { apiKey: _, auth: _auth, baseURL: _baseURL, queryParams: _queryParams, ...rest } = input + return rest } -export const responsesWebSocket = ( - id: string | ModelID, - options: OpenAIModelInput> = {}, -) => { - const { apiKey: _, ...rest } = options - return OpenAIResponses.webSocketModel( - withOpenAIOptions(id, { ...rest, auth: auth(options) }, { textVerbosity: true }), - ) +const configuredRoute = (route: Route, input: Config) => + route.with({ + auth: auth(input), + endpoint: { baseURL: input.baseURL, query: input.queryParams }, + }) + +export const configure = (input: Config = {}) => { + const responsesRoute = configuredRoute(OpenAIResponses.route, input) + const responsesWebSocketRoute = configuredRoute(OpenAIResponses.webSocketRoute, input) + const chatRoute = configuredRoute(OpenAIChat.route, input) + const modelDefaults = defaults(input) + const responses = (id: string | ModelID) => + responsesRoute.with(withOpenAIOptions(id, modelDefaults, { textVerbosity: true })).model({ id }) + const responsesWebSocket = (id: string | ModelID) => + responsesWebSocketRoute.with(withOpenAIOptions(id, modelDefaults, { textVerbosity: true })).model({ id }) + const chat = (id: string | ModelID) => chatRoute.with(withOpenAIOptions(id, modelDefaults)).model({ id }) + + return { + id, + model: responses, + responses, + responsesWebSocket, + chat, + configure, + } } -export const chat = (id: string | ModelID, options: OpenAIModelInput> = {}) => { - const { apiKey: _, ...rest } = options - return OpenAIChat.model(withOpenAIOptions(id, { ...rest, auth: auth(options) })) -} - -export const provider = Provider.make({ - id, - model: responses, - apis: { responses, responsesWebSocket, chat }, -}) +export const provider = configure() export const model = provider.model -export const apis = provider.apis +export const responses = provider.responses +export const responsesWebSocket = provider.responsesWebSocket +export const chat = provider.chat diff --git a/packages/llm/src/providers/openrouter.ts b/packages/llm/src/providers/openrouter.ts index 4c1a432106..914d7c0a0b 100644 --- a/packages/llm/src/providers/openrouter.ts +++ b/packages/llm/src/providers/openrouter.ts @@ -1,9 +1,9 @@ import { Effect, Schema } from "effect" -import { Route, type RouteModelInput } from "../route/client" +import { Route, type RouteDefaultsInput } from "../route/client" import { Endpoint } from "../route/endpoint" import { Framing } from "../route/framing" -import { Provider } from "../provider" import { Protocol } from "../route/protocol" +import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" import { ProviderID, type ModelID, type ProviderOptions } from "../schema" import * as OpenAICompatibleProfiles from "./openai-compatible-profile" import * as OpenAIChat from "../protocols/openai-chat" @@ -24,11 +24,11 @@ export type OpenRouterProviderOptionsInput = ProviderOptions & { readonly openrouter?: OpenRouterOptions } -export type ModelOptions = Omit & { - readonly baseURL?: string - readonly providerOptions?: OpenRouterProviderOptionsInput -} -type ModelInput = ModelOptions & Pick +export type ModelOptions = Omit & + ProviderAuthOption<"optional"> & { + readonly baseURL?: string + readonly providerOptions?: OpenRouterProviderOptionsInput + } const OpenRouterBody = Schema.StructWithRest(Schema.Struct(OpenAIChat.bodyFields), [ Schema.Record(Schema.String, Schema.Any), @@ -68,21 +68,31 @@ const bodyOptions = (input: unknown) => { export const route = Route.make({ id: ADAPTER, + provider: profile.provider, protocol, - endpoint: Endpoint.path("/chat/completions"), + endpoint: Endpoint.path("/chat/completions", { baseURL: profile.baseURL }), framing: Framing.sse, }) export const routes = [route] -const modelRef = Route.model(route, { - provider: profile.provider, - baseURL: profile.baseURL, -}) +const configuredRoute = (input: ModelOptions) => { + const { apiKey: _, auth: _auth, baseURL, ...rest } = input + return route.with({ + ...rest, + endpoint: { baseURL: baseURL ?? profile.baseURL }, + auth: AuthOptions.bearer(input, "OPENROUTER_API_KEY"), + }) +} -export const model = (id: string | ModelID, options: ModelOptions = {}) => modelRef({ ...options, id }) +export const configure = (input: ModelOptions = {}) => { + const route = configuredRoute(input) + return { + id, + model: (modelID: string | ModelID) => route.model({ id: modelID }), + configure, + } +} -export const provider = Provider.make({ - id, - model, -}) +export const provider = configure() +export const model = provider.model diff --git a/packages/llm/src/providers/xai.ts b/packages/llm/src/providers/xai.ts index 089c8c7339..321db97db1 100644 --- a/packages/llm/src/providers/xai.ts +++ b/packages/llm/src/providers/xai.ts @@ -1,7 +1,5 @@ import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" -import { Route } from "../route/client" -import type { RouteModelInput } from "../route/client" -import { Provider } from "../provider" +import type { RouteDefaultsInput } from "../route/client" import { ProviderID, type ModelID } from "../schema" import * as OpenAICompatibleProfiles from "./openai-compatible-profile" import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat" @@ -9,44 +7,50 @@ import * as OpenAIResponses from "../protocols/openai-responses" export const id = ProviderID.make("xai") -export type ModelOptions = Omit & +export type ModelOptions = RouteDefaultsInput & ProviderAuthOption<"optional"> & { readonly baseURL?: string } export const routes = [OpenAIResponses.route, OpenAICompatibleChat.route] -const responsesModel = Route.model(OpenAIResponses.route, { provider: id }) -const chatModel = OpenAICompatibleChat.model - const auth = (options: ProviderAuthOption<"optional">) => AuthOptions.bearer(options, "XAI_API_KEY") -export const responses = (modelID: string | ModelID, options: ModelOptions = {}) => { - const { apiKey: _, ...rest } = options - return responsesModel({ +const configuredResponsesRoute = (input: ModelOptions) => { + const { apiKey: _, auth: _auth, baseURL, ...rest } = input + return OpenAIResponses.route.with({ ...rest, - auth: auth(options), - id: modelID, - baseURL: options.baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL, - }) -} - -export const chat = (modelID: string | ModelID, options: ModelOptions = {}) => { - const { apiKey: _, ...rest } = options - return chatModel({ - ...rest, - auth: auth(options), - id: modelID, provider: id, - baseURL: options.baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL, + endpoint: { baseURL: baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL }, + auth: auth(input), }) } -export const provider = Provider.make({ - id, - model: responses, - apis: { responses, chat }, -}) +const configuredChatRoute = (input: ModelOptions) => { + const { apiKey: _, auth: _auth, baseURL, ...rest } = input + return OpenAICompatibleChat.route.with({ + ...rest, + provider: id, + endpoint: { baseURL: baseURL ?? OpenAICompatibleProfiles.profiles.xai.baseURL }, + auth: auth(input), + }) +} +export const configure = (input: ModelOptions = {}) => { + const responsesRoute = configuredResponsesRoute(input) + const chatRoute = configuredChatRoute(input) + const responses = (modelID: string | ModelID) => responsesRoute.model({ id: modelID }) + const chat = (modelID: string | ModelID) => chatRoute.model({ id: modelID }) + return { + id, + model: responses, + responses, + chat, + configure, + } +} + +export const provider = configure() export const model = provider.model -export const apis = provider.apis +export const responses = provider.responses +export const chat = provider.chat diff --git a/packages/llm/src/route/auth.ts b/packages/llm/src/route/auth.ts index b46e223363..32871c0454 100644 --- a/packages/llm/src/route/auth.ts +++ b/packages/llm/src/route/auth.ts @@ -12,6 +12,7 @@ export class MissingCredentialError extends Error { export type CredentialError = MissingCredentialError | Config.ConfigError export type AuthError = CredentialError | LLMError +type Secret = string | Redacted.Redacted | Config.Config export interface AuthInput { readonly request: LLMRequest @@ -22,7 +23,7 @@ export interface AuthInput { } export interface Credential { - readonly load: Effect.Effect, CredentialError> + readonly load: Effect.Effect readonly orElse: (that: Credential) => Credential readonly bearer: () => Auth readonly header: (name: string) => Auth @@ -39,7 +40,7 @@ export interface Auth { export const isAuth = (input: unknown): input is Auth => typeof input === "object" && input !== null && "apply" in input && typeof input.apply === "function" -const credential = (load: Effect.Effect, CredentialError>): Credential => { +const credential = (load: Effect.Effect): Credential => { const self: Credential = { load, orElse: (that) => credential(load.pipe(Effect.catch(() => that.load))), @@ -66,16 +67,13 @@ const fromCredential = (source: Credential, render: (secret: string) => Headers. source.load.pipe(Effect.map((secret) => Headers.setAll(input.headers, render(Redacted.value(secret))))), ) -const secretEffect = (secret: string | Redacted.Redacted, source: string) => { +const secretEffect = (secret: string | Redacted.Redacted, source: string) => { const redacted = typeof secret === "string" ? Redacted.make(secret) : secret if (Redacted.value(redacted) === "") return Effect.fail(new MissingCredentialError(source)) return Effect.succeed(redacted) } -const credentialFromSecret = ( - secret: string | Redacted.Redacted | Config.Config>, - source: string, -) => { +const credentialFromSecret = (secret: Secret, source: string) => { if (typeof secret === "string" || Redacted.isRedacted(secret)) return credential(secretEffect(secret, source)) return credential( Effect.gen(function* () { @@ -86,17 +84,14 @@ const credentialFromSecret = ( export const value = (secret: string, source = "value") => credentialFromSecret(secret, source) -export const optional = ( - secret: string | Redacted.Redacted | Config.Config> | undefined, - source = "optional value", -) => +export const optional = (secret: Secret | undefined, source = "optional value") => secret === undefined ? credential(Effect.fail(new MissingCredentialError(source))) : credentialFromSecret(secret, source) export const config = (name: string) => credentialFromSecret(Config.redacted(name), name) -export const effect = (load: Effect.Effect, CredentialError>) => credential(load) +export const effect = (load: Effect.Effect) => credential(load) export const none = auth((input) => Effect.succeed(input.headers)) @@ -109,68 +104,32 @@ export const custom = (apply: (input: AuthInput) => Effect.Effect Headers.Input) => - auth(({ request, headers }) => { - const key = request.model.apiKey - if (!key) return Effect.succeed(headers) - return Effect.succeed(Headers.setAll(headers, from(key))) - }) - -const credentialInput = ( - source: string | Redacted.Redacted | Config.Config> | Credential, -) => +const credentialInput = (source: Secret | Credential) => typeof source === "string" || Redacted.isRedacted(source) || Config.isConfig(source) ? credentialFromSecret(source, "value") : source -export function bearer(): Auth -export function bearer( - source: string | Redacted.Redacted | Config.Config> | Credential, -): Auth -export function bearer( - source?: string | Redacted.Redacted | Config.Config> | Credential, -) { - if (source === undefined) return fromModelApiKey((key) => ({ authorization: `Bearer ${key}` })) +export function bearer(source: Secret | Credential): Auth +export function bearer(source: Secret | Credential) { return credentialInput(source).bearer() } export const apiKey = bearer -export const apiKeyHeader = (name: string) => fromModelApiKey((key) => ({ [name]: key })) - -export function header( - name: string, -): (source: string | Redacted.Redacted | Config.Config> | Credential) => Auth -export function header( - name: string, - source: string | Redacted.Redacted | Config.Config> | Credential, -): Auth -export function header( - name: string, - source?: string | Redacted.Redacted | Config.Config> | Credential, -) { +export function header(name: string): (source: Secret | Credential) => Auth +export function header(name: string, source: Secret | Credential): Auth +export function header(name: string, source?: Secret | Credential) { if (source === undefined) { - return ( - next: string | Redacted.Redacted | Config.Config> | Credential, - ) => credentialInput(next).header(name) + return (next: Secret | Credential) => credentialInput(next).header(name) } return credentialInput(source).header(name) } -export function bearerHeader( - name: string, -): (source: string | Redacted.Redacted | Config.Config> | Credential) => Auth -export function bearerHeader( - name: string, - source: string | Redacted.Redacted | Config.Config> | Credential, -): Auth -export function bearerHeader( - name: string, - source?: string | Redacted.Redacted | Config.Config> | Credential, -) { - const render = ( - input: string | Redacted.Redacted | Config.Config> | Credential, - ) => fromCredential(credentialInput(input), (secret) => ({ [name]: `Bearer ${secret}` })) +export function bearerHeader(name: string): (source: Secret | Credential) => Auth +export function bearerHeader(name: string, source: Secret | Credential): Auth +export function bearerHeader(name: string, source?: Secret | Credential) { + const render = (input: Secret | Credential) => + fromCredential(credentialInput(input), (secret) => ({ [name]: `Bearer ${secret}` })) if (source === undefined) return render return render(source) } diff --git a/packages/llm/src/route/client.ts b/packages/llm/src/route/client.ts index 2d9de2fd39..6b5c47f768 100644 --- a/packages/llm/src/route/client.ts +++ b/packages/llm/src/route/client.ts @@ -1,31 +1,28 @@ import { Cause, Context, Effect, Layer, Schema, Stream } from "effect" -import type { Auth as AuthDef } from "./auth" -import type { Endpoint } from "./endpoint" +import * as Option from "effect/Option" +import { Auth, type Auth as AuthDef } from "./auth" +import { Endpoint, type EndpointPatch } from "./endpoint" import { RequestExecutor } from "./executor" import type { Framing } from "./framing" import { HttpTransport } from "./transport" import type { Transport, TransportRuntime } from "./transport" import { WebSocketExecutor } from "./transport" -import type { Service as WebSocketExecutorService } from "./transport/websocket" import type { Protocol } from "./protocol" import { applyCachePolicy } from "../cache-policy" import * as ProviderShared from "../protocols/shared" import * as ToolRuntime from "../tool-runtime" import type { Tools } from "../tool" -import type { LLMError, LLMEvent, PreparedRequestOf, ProtocolID } from "../schema" +import type { LLMError, LLMEvent, PreparedRequestOf, ProtocolID, ProviderOptions } from "../schema" import { GenerationOptions, HttpOptions, LLMRequest, LLMResponse, - ModelID, + Model, ModelLimits, - ModelRef, LLMError as LLMErrorClass, - NoRouteReason, PreparedRequest, ProviderID, - RouteID, mergeGenerationOptions, mergeHttpOptions, mergeProviderOptions, @@ -42,11 +39,13 @@ export interface Route { readonly id: string readonly provider?: ProviderID readonly protocol: ProtocolID + readonly endpoint: Endpoint + readonly auth: AuthDef readonly transport: Transport readonly defaults: RouteDefaults readonly body: RouteBody readonly with: (patch: RoutePatch) => Route - readonly model: (input: Input) => ModelRef + readonly model: (input: RouteMappedModelInput) => Model readonly prepareTransport: (body: Body, request: LLMRequest) => Effect.Effect readonly streamPrepared: ( prepared: Prepared, @@ -61,116 +60,77 @@ export interface Route { // oxlint-disable-next-line typescript-eslint/no-explicit-any export type AnyRoute = Route -const routeRegistry = new Map() - -// Route lookup is intentionally global: model refs name a route id, and -// importing the provider/protocol/custom-route module registers the runnable -// implementation. Duplicate ids are bugs because model refs cannot disambiguate -// them. -const register = (route: R): R => { - const existing = routeRegistry.get(route.id) - if (existing && existing !== route) throw new Error(`Duplicate LLM route id "${route.id}"`) - routeRegistry.set(route.id, route) - return route -} - -const registeredRoute = (id: string) => routeRegistry.get(id) - export type HttpOptionsInput = HttpOptions.Input -export type ModelRefInput = Omit< - ConstructorParameters[0], - "id" | "provider" | "route" | "limits" | "generation" | "http" | "auth" -> & { - readonly id: string | ModelID - readonly provider: string | ProviderID - readonly route: string | RouteID - readonly auth?: AuthDef +export type RouteModelInput = Omit + +export type RouteRoutedModelInput = Omit + +export interface RouteDefaults { + readonly headers?: Record + readonly limits?: ModelLimits + readonly generation?: GenerationOptions + readonly providerOptions?: ProviderOptions + readonly http?: HttpOptions +} + +export interface RouteDefaultsInput { + readonly headers?: Record readonly limits?: ModelLimits.Input readonly generation?: GenerationOptions.Input - readonly http?: HttpOptionsInput + readonly providerOptions?: ProviderOptions + readonly http?: HttpOptions.Input } -// `baseURL` is required on `ModelRefInput` (every materialized `ModelRef` has -// a host) but optional at the route-input layers below. The route's `defaults` -// can supply a canonical URL (e.g. OpenAI/Anthropic) so the user's input may -// omit it. Routes without a canonical URL (OpenAI-compatible, GitHub Copilot) -// re-tighten this in their own input type. -export type RouteModelInput = Omit & { - readonly baseURL?: string -} - -export type RouteModelDefaults = Omit & { - readonly baseURL?: string -} - -export type RouteRoutedModelInput = Omit & { - readonly baseURL?: string -} - -export type RouteRoutedModelDefaults = Partial> - -export type RouteDefaults = Partial> - -export interface RoutePatch extends RouteDefaults { - readonly id: string +export interface RoutePatch extends RouteDefaultsInput { + readonly id?: string readonly provider?: string | ProviderID + readonly auth?: AuthDef readonly transport?: Transport + readonly endpoint?: EndpointPatch } type RouteMappedModelInput = RouteModelInput | RouteRoutedModelInput -export interface RouteModelOptions< - Input extends RouteMappedModelInput, - Output extends RouteMappedModelInput = RouteMappedModelInput, -> { - readonly mapInput?: (input: Input) => Output +const makeRouteModel = (route: AnyRoute, mapped: RouteMappedModelInput) => { + const provider = route.provider ?? ("provider" in mapped ? mapped.provider : undefined) + if (!provider) throw new Error(`Route.model(${route.id}) requires a provider`) + if (!endpointBaseURL(route.endpoint)) + throw new Error(`Route.model(${route.id}) requires an endpoint baseURL — configure it on the route first`) + return Model.make({ + ...mapped, + provider, + route, + }) } -export interface RouteMappedModelOptions { - readonly mapInput: (input: Input) => Output -} - -const modelWithDefaults = - ( - route: AnyRoute, - defaults: Partial>, - options: { readonly mapInput?: (input: Input) => RouteMappedModelInput }, - ) => - (input: Input) => { - const mapped = options.mapInput === undefined ? (input as RouteMappedModelInput) : options.mapInput(input) - const provider = defaults.provider ?? route.provider ?? ("provider" in mapped ? mapped.provider : undefined) - if (!provider) throw new Error(`Route.model(${route.id}) requires a provider`) - const baseURL = mapped.baseURL ?? defaults.baseURL ?? route.defaults.baseURL - if (!baseURL) - throw new Error(`Route.model(${route.id}) requires a baseURL — supply it via input, defaults, or route defaults`) - const generation = mergeGenerationOptions(route.defaults.generation, defaults.generation) - const providerOptions = mergeProviderOptions(route.defaults.providerOptions, defaults.providerOptions) - const http = mergeHttpOptions(httpOptions(route.defaults.http), httpOptions(defaults.http)) - return modelRef({ - ...route.defaults, - ...defaults, - ...mapped, - baseURL, - provider, - route: route.id, - limits: mapped.limits ?? defaults.limits ?? route.defaults.limits, - generation: mergeGenerationOptions(generation, mapped.generation), - providerOptions: mergeProviderOptions(providerOptions, mapped.providerOptions), - http: mergeHttpOptions(http, httpOptions(mapped.http)), - }) +const mergeRouteDefaults = (base: RouteDefaults | undefined, patch: RouteDefaultsInput): RouteDefaults => { + const headers = mergeHeaders(base?.headers, patch.headers) + return { + ...base, + ...patch, + headers, + limits: patch.limits === undefined ? base?.limits : ModelLimits.make(patch.limits), + generation: mergeGenerationOptions(generationOptions(base?.generation), generationOptions(patch.generation)), + providerOptions: mergeProviderOptions(base?.providerOptions, patch.providerOptions), + http: mergeHttpOptions( + base?.http, + httpOptions(patch.http), + headers === undefined ? undefined : new HttpOptions({ headers }), + ), } +} -const mergeRouteDefaults = (base: RouteDefaults | undefined, patch: RouteDefaults): RouteDefaults => ({ - ...base, - ...patch, - limits: patch.limits ?? base?.limits, - generation: mergeGenerationOptions(generationOptions(base?.generation), generationOptions(patch.generation)), - providerOptions: mergeProviderOptions(base?.providerOptions, patch.providerOptions), - http: mergeHttpOptions(httpOptions(base?.http), httpOptions(patch.http)), -}) +const endpointBaseURL = (endpoint: Endpoint) => + typeof endpoint.baseURL === "string" ? endpoint.baseURL : undefined -export const modelLimits = ModelLimits.make +const mergeHeaders = (...items: ReadonlyArray | undefined>) => { + const entries = items.flatMap((item) => + item === undefined ? [] : Object.entries(item).filter((entry): entry is [string, string] => entry[1] !== undefined), + ) + if (entries.length === 0) return undefined + return Object.fromEntries(entries) +} export const generationOptions = (input: GenerationOptions.Input | undefined) => input === undefined ? undefined : GenerationOptions.make(input) @@ -180,40 +140,6 @@ export const httpOptions = (input: HttpOptionsInput | undefined) => { return HttpOptions.make(input) } -export const modelRef = (input: ModelRefInput) => - new ModelRef({ - ...input, - id: ModelID.make(input.id), - provider: ProviderID.make(input.provider), - route: RouteID.make(input.route), - limits: modelLimits(input.limits), - generation: generationOptions(input.generation), - http: httpOptions(input.http), - }) - -function model( - route: AnyRoute, - defaults: RouteModelDefaults, - options?: RouteModelOptions, -): (input: Input) => ModelRef -function model( - route: AnyRoute, - defaults?: RouteRoutedModelDefaults, - options?: RouteModelOptions, -): (input: Input) => ModelRef -function model( - route: AnyRoute, - defaults: Partial>, - options: RouteMappedModelOptions, -): (input: Input) => ModelRef -function model( - route: AnyRoute, - defaults: Partial> = {}, - options: { readonly mapInput?: (input: Input) => RouteMappedModelInput } = {}, -) { - return modelWithDefaults(route, defaults, options) -} - export interface Interface { /** * Compile a request through protocol body construction, validation, and HTTP @@ -242,22 +168,16 @@ export interface GenerateMethod { export class Service extends Context.Service()("@opencode/LLMClient") {} -const noRoute = (model: ModelRef) => - new LLMErrorClass({ - module: "LLMClient", - method: "resolveRoute", - reason: new NoRouteReason({ route: model.route, provider: model.provider, model: model.id }), - }) - const resolveRequestOptions = (request: LLMRequest) => LLMRequest.update(request, { - generation: mergeGenerationOptions(request.model.generation, request.generation) ?? new GenerationOptions({}), - providerOptions: mergeProviderOptions(request.model.providerOptions, request.providerOptions), - http: mergeHttpOptions(request.model.http, request.http), + generation: + mergeGenerationOptions(request.model.route.defaults.generation, request.generation) ?? new GenerationOptions({}), + providerOptions: mergeProviderOptions(request.model.route.defaults.providerOptions, request.providerOptions), + http: mergeHttpOptions(request.model.route.defaults.http, request.http), }) export interface MakeInput { - /** Route id used in registry lookup and error messages. */ + /** Route id used in diagnostics and prepared request metadata. */ readonly id: string /** Provider identity for route-owned model construction. */ readonly provider?: string | ProviderID @@ -265,27 +185,33 @@ export interface MakeInput { readonly protocol: Protocol /** Where the request is sent. */ readonly endpoint: Endpoint - /** Per-request transport auth. Model-level `Auth` overrides this. */ + /** Per-request transport auth. Provider facades override this via `route.with(...)`. */ readonly auth?: AuthDef /** Stream framing — bytes -> frames before `protocol.stream.event` decoding. */ readonly framing: Framing /** Static / per-request headers added before `auth` runs. */ readonly headers?: (input: { readonly request: LLMRequest }) => Record - /** Model defaults used by the route's `.model(...)` helper. */ - readonly defaults?: RouteDefaults + /** Route/request defaults used when compiling requests for this route. */ + readonly defaults?: RouteDefaultsInput } export interface MakeTransportInput { - /** Route id used in registry lookup and error messages. */ + /** Route id used in diagnostics and prepared request metadata. */ readonly id: string /** Provider identity for route-owned model construction. */ readonly provider?: string | ProviderID /** Semantic API contract — owns body construction, body schema, and parsing. */ readonly protocol: Protocol + /** Where the request is sent. */ + readonly endpoint: Endpoint + /** Per-request transport auth. Provider facades override this via `route.with(...)`. */ + readonly auth?: AuthDef + /** Static / per-request headers added before `auth` runs. */ + readonly headers?: (input: { readonly request: LLMRequest }) => Record /** Runnable transport route. */ readonly transport: Transport - /** Provider/model defaults used by the route's `.model(...)` helper. */ - readonly defaults?: RouteDefaults + /** Route/request defaults used when compiling requests for this route. */ + readonly defaults?: RouteDefaultsInput } const streamError = (route: string, message: string, cause: Cause.Cause) => { @@ -298,6 +224,7 @@ function makeFromTransport( input: MakeTransportInput, ): Route { const protocol = input.protocol + const encodeBody = Schema.encodeSync(Schema.fromJsonString(protocol.body.schema)) const decodeEventEffect = Schema.decodeUnknownEffect(protocol.stream.event) const decodeEvent = (route: string) => (frame: Frame) => decodeEventEffect(frame).pipe( @@ -310,29 +237,44 @@ function makeFromTransport( ), ) - const build = (routeInput: MakeTransportInput): Route => { + type BuiltRouteInput = Omit, "defaults"> & { + readonly defaults?: RouteDefaults + } + + const build = (routeInput: BuiltRouteInput): Route => { const route: Route = { id: routeInput.id, provider: routeInput.provider === undefined ? undefined : ProviderID.make(routeInput.provider), protocol: protocol.id, + endpoint: routeInput.endpoint, + auth: routeInput.auth ?? Auth.none, transport: routeInput.transport, defaults: routeInput.defaults ?? {}, body: protocol.body, with: (patch: RoutePatch) => { - const { id, provider, transport, ...defaults } = patch - if (!id || id === routeInput.id) throw new Error(`Route.with(${routeInput.id}) requires a new route id`) + const { id, provider, auth, transport, endpoint, ...defaults } = patch return build({ ...routeInput, - id, + id: id ?? routeInput.id, provider: provider ?? routeInput.provider, + auth: auth ?? routeInput.auth, + endpoint: endpoint ? Endpoint.merge(routeInput.endpoint, endpoint) : routeInput.endpoint, transport: (transport as Transport | undefined) ?? routeInput.transport, - defaults: mergeRouteDefaults(routeInput.defaults, defaults), + defaults: mergeRouteDefaults(route.defaults, defaults), }) }, - model: (input: RouteModelInput): ModelRef => modelWithDefaults(route, {}, {})(input), - prepareTransport: routeInput.transport.prepare, + model: (input) => makeRouteModel(route, input), + prepareTransport: (body, request) => + routeInput.transport.prepare({ + body, + request, + endpoint: routeInput.endpoint, + auth: routeInput.auth ?? Auth.none, + encodeBody, + headers: routeInput.headers, + }), streamPrepared: (prepared: Prepared, request: LLMRequest, runtime: TransportRuntime) => { - const route = `${request.model.provider}/${request.model.route}` + const route = `${request.model.provider}/${request.model.route.id}` const events = routeInput.transport .frames(prepared, request, runtime) .pipe( @@ -349,10 +291,10 @@ function makeFromTransport( ) }, } satisfies Route - return register(route) + return route } - return build(input) + return build({ ...input, defaults: mergeRouteDefaults(undefined, input.defaults ?? {}) }) } export function make( @@ -381,18 +323,14 @@ export function make( ): Route | Route> { if ("transport" in input) return makeFromTransport(input) const protocol = input.protocol - const encodeBody = Schema.encodeSync(Schema.fromJsonString(protocol.body.schema)) return makeFromTransport({ id: input.id, provider: input.provider, protocol, - transport: HttpTransport.httpJson({ - endpoint: input.endpoint, - auth: input.auth, - framing: input.framing, - encodeBody, - headers: input.headers, - }), + endpoint: input.endpoint, + auth: input.auth, + headers: input.headers, + transport: HttpTransport.httpJson({ framing: input.framing }), defaults: input.defaults, }) } @@ -402,8 +340,7 @@ export function make( // execute transport. const compile = Effect.fn("LLM.compile")(function* (request: LLMRequest) { const resolved = applyCachePolicy(resolveRequestOptions(request)) - const route = registeredRoute(resolved.model.route) - if (!route) return yield* noRoute(resolved.model) + const route = resolved.model.route const body = yield* route.body .from(resolved) @@ -495,31 +432,21 @@ export const streamRequest = (request: LLMRequest) => export const layer: Layer.Layer = Layer.effect( Service, Effect.gen(function* () { - const stream = streamWith(streamRequestWith({ http: yield* RequestExecutor.Service })) + const stream = streamWith( + streamRequestWith({ + http: yield* RequestExecutor.Service, + webSocket: Option.getOrUndefined(yield* Effect.serviceOption(WebSocketExecutor.Service)), + }), + ) return Service.of({ prepare: prepareWith as Interface["prepare"], stream, generate: generateWith(stream) }) }), ) -export const layerWithWebSocket: Layer.Layer = - Layer.effect( - Service, - Effect.gen(function* () { - const stream = streamWith( - streamRequestWith({ - http: yield* RequestExecutor.Service, - webSocket: yield* WebSocketExecutor.Service, - }), - ) - return Service.of({ prepare: prepareWith as Interface["prepare"], stream, generate: generateWith(stream) }) - }), - ) - -export const Route = { make, model } as const +export const Route = { make } as const export const LLMClient = { Service, layer, - layerWithWebSocket, prepare, stream, generate, diff --git a/packages/llm/src/route/endpoint.ts b/packages/llm/src/route/endpoint.ts index 361ad508e1..accbe53243 100644 --- a/packages/llm/src/route/endpoint.ts +++ b/packages/llm/src/route/endpoint.ts @@ -11,28 +11,42 @@ export type EndpointPart = string | ((input: EndpointInput) => strin /** * Declarative URL construction for one route. * - * `Endpoint` carries only the path. The host always lives on `model.baseURL`, - * supplied by the provider helper that constructs the model. `render(...)` - * just appends the path (and any `model.queryParams`) to that host. + * `Endpoint` carries URL construction for one route. Routes with a canonical + * host put `baseURL` here; provider helpers can override it by configuring the + * route before selecting a model. * * `path` may be a string or a function of `EndpointInput`, for routes whose * URL embeds the model id, region, or another body field (e.g. Bedrock, * Gemini). */ export interface Endpoint { + readonly baseURL?: string readonly path: EndpointPart + readonly query?: Record } +export type EndpointPatch = Partial> + /** Construct an `Endpoint` from a path string or path function. */ -export const path = (value: EndpointPart): Endpoint => ({ path: value }) +export const path = (value: EndpointPart, options: Omit, "path"> = {}): Endpoint => ({ + ...options, + path: value, +}) + +export const merge = (base: Endpoint, patch: EndpointPatch): Endpoint => ({ + ...base, + ...patch, + baseURL: patch.baseURL ?? base.baseURL, + path: patch.path ?? base.path, + query: patch.query === undefined ? base.query : { ...base.query, ...patch.query }, +}) const renderPart = (part: EndpointPart, input: EndpointInput) => typeof part === "function" ? part(input) : part export const render = (endpoint: Endpoint, input: EndpointInput) => { - const url = new URL(`${ProviderShared.trimBaseUrl(input.request.model.baseURL)}${renderPart(endpoint.path, input)}`) - const params = input.request.model.queryParams - if (params) for (const [key, value] of Object.entries(params)) url.searchParams.set(key, value) + const url = new URL(`${ProviderShared.trimBaseUrl(endpoint.baseURL ?? "")}${renderPart(endpoint.path, input)}`) + for (const [key, value] of Object.entries(endpoint.query ?? {})) url.searchParams.set(key, value) return url } diff --git a/packages/llm/src/route/index.ts b/packages/llm/src/route/index.ts index a75dd3e038..48f4b7bc33 100644 --- a/packages/llm/src/route/index.ts +++ b/packages/llm/src/route/index.ts @@ -1,14 +1,13 @@ -export { Route, LLMClient, modelLimits, modelRef } from "./client" +export { Route, LLMClient } from "./client" export type { Route as RouteShape, - RouteModelDefaults, RouteModelInput, - RouteRoutedModelDefaults, RouteRoutedModelInput, + RouteDefaults, + RouteDefaultsInput, AnyRoute, Interface as LLMClientShape, Service as LLMClientService, - ModelRefInput, } from "./client" export * from "./executor" export { Auth } from "./auth" diff --git a/packages/llm/src/route/transport/http.ts b/packages/llm/src/route/transport/http.ts index 2159ce90b0..00508957a7 100644 --- a/packages/llm/src/route/transport/http.ts +++ b/packages/llm/src/route/transport/http.ts @@ -1,20 +1,13 @@ import { Effect, Stream } from "effect" import { Headers, HttpClientRequest } from "effect/unstable/http" -import { Auth, type Auth as AuthDef } from "../auth" -import { type Endpoint, render as renderEndpoint } from "../endpoint" -import type { Framing } from "../framing" -import type { Transport } from "./index" +import { Auth } from "../auth" +import { render as renderEndpoint } from "../endpoint" +import { Framing, type Framing as FramingDef } from "../framing" +import type { Transport, TransportPrepareInput } from "./index" import * as ProviderShared from "../../protocols/shared" import { mergeJsonRecords, type LLMRequest } from "../../schema" -export interface JsonRequestInput { - readonly body: Body - readonly request: LLMRequest - readonly endpoint: Endpoint - readonly auth: AuthDef - readonly encodeBody: (body: Body) => string - readonly headers?: (input: { readonly request: LLMRequest }) => Record -} +export type JsonRequestInput = TransportPrepareInput export interface JsonRequestParts { readonly url: string @@ -25,7 +18,7 @@ export interface JsonRequestParts { export interface HttpPrepared { readonly request: HttpClientRequest.HttpClientRequest - readonly framing: Framing + readonly framing: FramingDef } const applyQuery = (url: string, query: Record | undefined) => { @@ -52,28 +45,21 @@ export const jsonRequestParts = (input: JsonRequestInput) => input.request.http?.query, ) const body = yield* bodyWithOverlay(input.body, input.request, input.encodeBody) - const headers = yield* Auth.toEffect(Auth.isAuth(input.request.model.auth) ? input.request.model.auth : input.auth)( - { - request: input.request, - method: "POST", - url, - body: body.bodyText, - headers: Headers.fromInput({ - ...(input.headers?.({ request: input.request }) ?? {}), - ...input.request.model.headers, - ...input.request.http?.headers, - }), - }, - ) + const headers = yield* Auth.toEffect(input.auth)({ + request: input.request, + method: "POST", + url, + body: body.bodyText, + headers: Headers.fromInput({ + ...input.headers?.({ request: input.request }), + ...input.request.http?.headers, + }), + }) return { url, jsonBody: body.jsonBody, bodyText: body.bodyText, headers } }) -export interface HttpJsonInput { - readonly endpoint: Endpoint - readonly auth?: AuthDef - readonly framing: Framing - readonly encodeBody: (body: Body) => string - readonly headers?: (input: { readonly request: LLMRequest }) => Record +export interface HttpJsonInput<_Body, Frame> { + readonly framing: FramingDef } export type HttpJsonPatch = Partial> @@ -85,14 +71,9 @@ export interface HttpJsonTransport extends Transport(input: HttpJsonInput): HttpJsonTransport => ({ id: "http-json", with: (patch) => httpJson({ ...input, ...patch }), - prepare: (body, request) => + prepare: (prepareInput) => jsonRequestParts({ - body, - request, - endpoint: input.endpoint, - auth: input.auth ?? Auth.bearer(), - encodeBody: input.encodeBody, - headers: input.headers, + ...prepareInput, }).pipe( Effect.map((parts) => ({ request: ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }), @@ -109,8 +90,8 @@ export const httpJson = (input: HttpJsonInput): HttpJs response.stream.pipe( Stream.mapError((error) => ProviderShared.eventError( - `${request.model.provider}/${request.model.route}`, - `Failed to read ${request.model.provider}/${request.model.route} stream`, + `${request.model.provider}/${request.model.route.id}`, + `Failed to read ${request.model.provider}/${request.model.route.id} stream`, ProviderShared.errorText(error), ), ), @@ -120,3 +101,8 @@ export const httpJson = (input: HttpJsonInput): HttpJs ), ), }) + +export const sseJson = { + id: "http-json/sse", + with: () => httpJson({ framing: Framing.sse }), +} as const diff --git a/packages/llm/src/route/transport/index.ts b/packages/llm/src/route/transport/index.ts index f4d5fb29b7..fde9d6c415 100644 --- a/packages/llm/src/route/transport/index.ts +++ b/packages/llm/src/route/transport/index.ts @@ -1,4 +1,6 @@ import type { Effect, Stream } from "effect" +import type { Endpoint } from "../endpoint" +import type { Auth } from "../auth" import type { Interface as RequestExecutorInterface } from "../executor" import type { Interface as WebSocketExecutorInterface } from "./websocket" import type { LLMError, LLMRequest } from "../../schema" @@ -10,7 +12,7 @@ export interface TransportRuntime { export interface Transport { readonly id: string - readonly prepare: (body: Body, request: LLMRequest) => Effect.Effect + readonly prepare: (input: TransportPrepareInput) => Effect.Effect readonly frames: ( prepared: Prepared, request: LLMRequest, @@ -18,5 +20,14 @@ export interface Transport { ) => Stream.Stream } +export interface TransportPrepareInput { + readonly body: Body + readonly request: LLMRequest + readonly endpoint: Endpoint + readonly auth: Auth + readonly encodeBody: (body: Body) => string + readonly headers?: (input: { readonly request: LLMRequest }) => Record +} + export * as HttpTransport from "./http" export { WebSocketExecutor, WebSocketTransport } from "./websocket" diff --git a/packages/llm/src/route/transport/websocket.ts b/packages/llm/src/route/transport/websocket.ts index 647a6db43d..310121420c 100644 --- a/packages/llm/src/route/transport/websocket.ts +++ b/packages/llm/src/route/transport/websocket.ts @@ -1,8 +1,6 @@ -import { Cause, Context, Effect, Queue, Stream } from "effect" +import { Cause, Context, Effect, Layer, Queue, Stream } from "effect" import { Headers } from "effect/unstable/http" -import { Auth, type Auth as AuthDef } from "../auth" -import type { Endpoint } from "../endpoint" -import { LLMError, TransportReason, type LLMRequest } from "../../schema" +import { LLMError, TransportReason } from "../../schema" import * as HttpTransport from "./http" import type { Transport } from "./index" @@ -135,6 +133,8 @@ export const open = (input: WebSocketRequest) => }), }).pipe(Effect.flatMap((ws) => fromWebSocket(ws, input))) +export const layer: Layer.Layer = Layer.succeed(Service, Service.of({ open })) + export const fromWebSocket = ( ws: globalThis.WebSocket, input: WebSocketRequest, @@ -213,12 +213,8 @@ export interface JsonPrepared { } export interface JsonInput { - readonly endpoint: Endpoint - readonly auth?: AuthDef - readonly encodeBody: (body: Body) => string readonly toMessage: (body: Body | Record) => Effect.Effect readonly encodeMessage: (message: Message) => string - readonly headers?: (input: { readonly request: LLMRequest }) => Record } export type JsonPatch = Partial> @@ -230,15 +226,10 @@ export interface JsonTransport extends Transport(input: JsonInput): JsonTransport => ({ id: "websocket-json", with: (patch) => json({ ...input, ...patch }), - prepare: (body, request) => + prepare: (prepareInput) => Effect.gen(function* () { const parts = yield* HttpTransport.jsonRequestParts({ - body, - request, - endpoint: input.endpoint, - auth: input.auth ?? Auth.bearer(), - encodeBody: input.encodeBody, - headers: input.headers, + ...prepareInput, }) return { url: yield* webSocketUrl(parts.url), @@ -270,8 +261,14 @@ export const json = (input: JsonInput): JsonTransp }, }) +export const jsonTransport = { + id: "websocket-json", + with: json, +} as const + export const WebSocketExecutor = { Service, + layer, open, fromWebSocket, messageText, @@ -279,4 +276,5 @@ export const WebSocketExecutor = { export const WebSocketTransport = { json, + jsonTransport, } as const diff --git a/packages/llm/src/schema/events.ts b/packages/llm/src/schema/events.ts index 63c9b7b7df..dd3e6d0362 100644 --- a/packages/llm/src/schema/events.ts +++ b/packages/llm/src/schema/events.ts @@ -1,6 +1,6 @@ import { Schema } from "effect" import { ContentBlockID, FinishReason, ProtocolID, ProviderMetadata, RouteID, ToolCallID } from "./ids" -import { ModelRef } from "./options" +import { ModelSchema } from "./options" import { ToolResultValue } from "./messages" /** @@ -91,6 +91,7 @@ export const TextDelta = Schema.Struct({ type: Schema.tag("text-delta"), id: ContentBlockID, text: Schema.String, + providerMetadata: Schema.optional(ProviderMetadata), }).annotate({ identifier: "LLM.Event.TextDelta" }) export type TextDelta = Schema.Schema.Type @@ -112,6 +113,7 @@ export const ReasoningDelta = Schema.Struct({ type: Schema.tag("reasoning-delta"), id: ContentBlockID, text: Schema.String, + providerMetadata: Schema.optional(ProviderMetadata), }).annotate({ identifier: "LLM.Event.ReasoningDelta" }) export type ReasoningDelta = Schema.Schema.Type @@ -288,7 +290,7 @@ export class PreparedRequest extends Schema.Class("LLM.Prepared id: Schema.String, route: RouteID, protocol: ProtocolID, - model: ModelRef, + model: ModelSchema, body: Schema.Unknown, metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), }) {} diff --git a/packages/llm/src/schema/messages.ts b/packages/llm/src/schema/messages.ts index c38a66d33d..9e19afce62 100644 --- a/packages/llm/src/schema/messages.ts +++ b/packages/llm/src/schema/messages.ts @@ -1,9 +1,7 @@ import { Schema } from "effect" import { JsonSchema, MessageRole, ProviderMetadata } from "./ids" -import { CacheHint, CachePolicy, GenerationOptions, HttpOptions, ModelRef, ProviderOptions } from "./options" - -const isRecord = (value: unknown): value is Record => - typeof value === "object" && value !== null && !Array.isArray(value) +import { CacheHint, CachePolicy, GenerationOptions, HttpOptions, ModelSchema, ProviderOptions } from "./options" +import { isRecord } from "../utils/record" const systemPartSchema = Schema.Struct({ type: Schema.Literal("text"), @@ -41,17 +39,49 @@ export const MediaPart = Schema.Struct({ }).annotate({ identifier: "LLM.Content.Media" }) export type MediaPart = Schema.Schema.Type +export const ToolResultMediaPart = Schema.Struct({ + type: Schema.Literal("media"), + mediaType: Schema.String, + data: Schema.String, + filename: Schema.optional(Schema.String), + metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), +}).annotate({ identifier: "LLM.ToolResult.Media" }) +export type ToolResultMediaPart = Schema.Schema.Type + +export const ToolResultContentPart = Schema.Union([TextPart, ToolResultMediaPart]) +export type ToolResultContentPart = Schema.Schema.Type + const isToolResultValue = (value: unknown): value is ToolResultValue => - isRecord(value) && (value.type === "text" || value.type === "json" || value.type === "error") && "value" in value + isRecord(value) && + (value.type === "text" || value.type === "json" || value.type === "error" || value.type === "content") && + "value" in value export const ToolResultValue = Object.assign( - Schema.Struct({ - type: Schema.Literals(["json", "text", "error"]), - value: Schema.Unknown, - }).annotate({ identifier: "LLM.ToolResult" }), + Schema.Union([ + Schema.Struct({ + type: Schema.Literal("json"), + value: Schema.Unknown, + }), + Schema.Struct({ + type: Schema.Literal("text"), + value: Schema.Unknown, + }), + Schema.Struct({ + type: Schema.Literal("error"), + value: Schema.Unknown, + }), + Schema.Struct({ + type: Schema.Literal("content"), + value: Schema.Array(ToolResultContentPart), + }), + ]).annotate({ identifier: "LLM.ToolResult" }), { - make: (value: unknown, type: ToolResultValue["type"] = "json"): ToolResultValue => - isToolResultValue(value) ? value : { type, value }, + is: isToolResultValue, + make: (value: unknown, type: ToolResultValue["type"] = "json"): ToolResultValue => { + if (isToolResultValue(value)) return value + if (type === "content") return { type, value: Array.isArray(value) ? value : [] } + return { type, value } + }, }, ) export type ToolResultValue = Schema.Schema.Type @@ -197,7 +227,7 @@ export type ResponseFormat = Schema.Schema.Type export class LLMRequest extends Schema.Class("LLM.Request")({ id: Schema.optional(Schema.String), - model: ModelRef, + model: ModelSchema, system: Schema.Array(SystemPart), messages: Schema.Array(Message), tools: Schema.Array(ToolDefinition), diff --git a/packages/llm/src/schema/options.ts b/packages/llm/src/schema/options.ts index 0f40196f7d..c02af6d1ed 100644 --- a/packages/llm/src/schema/options.ts +++ b/packages/llm/src/schema/options.ts @@ -1,8 +1,7 @@ import { Schema } from "effect" -import { JsonSchema, ModelID, ProviderID, RouteID } from "./ids" - -const isRecord = (value: unknown): value is Record => - typeof value === "object" && value !== null && !Array.isArray(value) +import { JsonSchema, ModelID, ProviderID } from "./ids" +import type { AnyRoute } from "../route/client" +import { isRecord } from "../utils/record" export const mergeJsonRecords = ( ...items: ReadonlyArray | undefined> @@ -135,67 +134,59 @@ export namespace ModelLimits { input instanceof ModelLimits ? input : new ModelLimits(input ?? {}) } -export class ModelRef extends Schema.Class("LLM.ModelRef")({ - id: ModelID, - provider: ProviderID, - route: RouteID, - baseURL: Schema.String, - /** Provider-specific API key convenience. Provider helpers normalize this into `auth`. */ - apiKey: Schema.optional(Schema.String), - /** Optional transport auth policy. Opaque because it may contain functions. */ - auth: Schema.optional(Schema.Any), - headers: Schema.optional(Schema.Record(Schema.String, Schema.String)), - /** - * Query params appended to the request URL by `Endpoint.baseURL`. Used for - * deployment-level URL-scoped settings such as Azure's `api-version` or any - * provider that requires a per-request key in the URL. Generic concern, so - * lives as a typed first-class field instead of `native`. - */ - queryParams: Schema.optional(Schema.Record(Schema.String, Schema.String)), - limits: ModelLimits, - /** Provider-neutral generation defaults. Request-level values override them. */ - generation: Schema.optional(GenerationOptions), - /** Provider-owned typed-at-the-facade options for non-portable knobs. */ - providerOptions: Schema.optional(ProviderOptions), - /** Serializable raw HTTP overlays applied to the final outgoing request. */ - http: Schema.optional(HttpOptions), - /** - * Provider-specific opaque options. Reach for this only when the value is - * genuinely provider-private and does not fit a typed axis (e.g. Bedrock's - * `aws_credentials` / `aws_region` for SigV4). Anything used by more than - * one route should grow into a typed field instead. - */ - native: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), -}) {} +export class Model { + readonly id: ModelID + readonly provider: ProviderID + readonly route: AnyRoute -export namespace ModelRef { - export type Input = ConstructorParameters[0] + constructor(input: Model.ConstructorInput) { + this.id = input.id + this.provider = input.provider + this.route = input.route + } - export const input = (model: ModelRef): Input => ({ - id: model.id, - provider: model.provider, - route: model.route, - baseURL: model.baseURL, - apiKey: model.apiKey, - auth: model.auth, - headers: model.headers, - queryParams: model.queryParams, - limits: model.limits, - generation: model.generation, - providerOptions: model.providerOptions, - http: model.http, - native: model.native, - }) + static make(input: Model.Input) { + return new Model({ + id: ModelID.make(input.id), + provider: ProviderID.make(input.provider), + route: input.route, + }) + } - export const update = (model: ModelRef, patch: Partial) => { + static input(model: Model): Model.ConstructorInput { + return { + id: model.id, + provider: model.provider, + route: model.route, + } + } + + static update(model: Model, patch: Partial) { if (Object.keys(patch).length === 0) return model - return new ModelRef({ - ...input(model), + return Model.make({ + ...Model.input(model), ...patch, }) } } +export namespace Model { + export type ConstructorInput = { + readonly id: ModelID + readonly provider: ProviderID + readonly route: AnyRoute + } + + export type Input = Omit & { + readonly id: string | ModelID + readonly provider: string | ProviderID + } +} + +export type ModelInput = Model.Input + +export const ModelSchema = Schema.declare((value): value is Model => value instanceof Model, { expected: "LLM.Model" }) + export class CacheHint extends Schema.Class("LLM.CacheHint")({ type: Schema.Literals(["ephemeral", "persistent"]), ttlSeconds: Schema.optional(Schema.Number), diff --git a/packages/llm/src/tool-runtime.ts b/packages/llm/src/tool-runtime.ts index ef527faa21..4f6bc83407 100644 --- a/packages/llm/src/tool-runtime.ts +++ b/packages/llm/src/tool-runtime.ts @@ -11,7 +11,8 @@ import { ToolCallPart, ToolFailure, ToolResultPart, - type ToolResultValue, + ToolResultValue, + type ToolResultValue as ToolResultValueType, Usage, } from "./schema" import { type AnyTool, type ExecutableTools, type Tools, toDefinitions } from "./tool" @@ -276,7 +277,10 @@ const appendStreamingText = ( state.assistantContent.push({ type, text, providerMetadata }) } -const dispatch = (tools: Tools, call: ToolCallPart): Effect.Effect<{ result: ToolResultValue; error?: unknown }> => { +const dispatch = ( + tools: Tools, + call: ToolCallPart, +): Effect.Effect<{ result: ToolResultValueType; error?: unknown }> => { const tool = tools[call.name] if (!tool) return Effect.succeed({ result: { type: "error" as const, value: `Unknown tool: ${call.name}` } }) if (!tool.execute) @@ -285,7 +289,7 @@ const dispatch = (tools: Tools, call: ToolCallPart): Effect.Effect<{ result: Too return decodeAndExecute(tool, call).pipe( Effect.catchTag("LLM.ToolFailure", (failure) => Effect.succeed({ - result: { type: "error" as const, value: failure.message } satisfies ToolResultValue, + result: { type: "error" as const, value: failure.message } satisfies ToolResultValueType, error: failure.error, }), ), @@ -293,7 +297,7 @@ const dispatch = (tools: Tools, call: ToolCallPart): Effect.Effect<{ result: Too ) } -const decodeAndExecute = (tool: AnyTool, call: ToolCallPart): Effect.Effect => +const decodeAndExecute = (tool: AnyTool, call: ToolCallPart): Effect.Effect => tool._decode(call.input).pipe( Effect.mapError((error) => new ToolFailure({ message: `Invalid tool input: ${error.message}` })), Effect.flatMap((decoded) => tool.execute!(decoded, { id: call.id, name: call.name })), @@ -307,10 +311,12 @@ const decodeAndExecute = (tool: AnyTool, call: ToolCallPart): Effect.Effect ({ type: "json", value: encoded })), + Effect.map( + (encoded): ToolResultValueType => (ToolResultValue.is(encoded) ? encoded : { type: "json", value: encoded }), + ), ) -const emitEvents = (call: ToolCallPart, result: ToolResultValue, error: unknown): ReadonlyArray => +const emitEvents = (call: ToolCallPart, result: ToolResultValueType, error: unknown): ReadonlyArray => result.type === "error" ? [ LLMEvent.toolError({ id: call.id, name: call.name, message: String(result.value), error }), @@ -321,7 +327,7 @@ const emitEvents = (call: ToolCallPart, result: ToolResultValue, error: unknown) const followUpRequest = ( request: LLMRequest, state: StepState, - dispatched: ReadonlyArray, + dispatched: ReadonlyArray, ) => LLMRequest.update(request, { messages: [ diff --git a/packages/llm/src/utils/record.ts b/packages/llm/src/utils/record.ts new file mode 100644 index 0000000000..a121fbde11 --- /dev/null +++ b/packages/llm/src/utils/record.ts @@ -0,0 +1,3 @@ +/** Plain-record narrowing. Excludes arrays so JSON object checks don't accept tuples as key/value bags. */ +export const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) diff --git a/packages/llm/test/adapter.test.ts b/packages/llm/test/adapter.test.ts index 80349a5ae5..8e182948fa 100644 --- a/packages/llm/test/adapter.test.ts +++ b/packages/llm/test/adapter.test.ts @@ -1,12 +1,12 @@ import { describe, expect } from "bun:test" import { Effect, Schema, Stream } from "effect" import { LLM } from "../src" -import { Route, Endpoint, LLMClient, Protocol, type RouteModelInput, type FramingDef } from "../src/route" -import { ModelRef } from "../src/schema" +import { Route, Endpoint, LLMClient, Protocol, type FramingDef } from "../src/route" +import { Model } from "../src/schema" import { testEffect } from "./lib/effect" import { dynamicResponse } from "./lib/http" -const updateModel = (model: ModelRef, patch: Partial) => ModelRef.update(model, patch) +const updateModel = (model: Model, patch: Partial) => Model.update(model, patch) const Json = Schema.fromJsonString(Schema.Unknown) const encodeJson = Schema.encodeSync(Json) @@ -38,17 +38,6 @@ const fakeFraming: FramingDef = { ).pipe(Stream.flatMap(Stream.fromIterable)), } -const request = LLM.request({ - id: "req_1", - model: LLM.model({ - id: "fake-model", - provider: "fake-provider", - route: "fake", - baseURL: "https://fake.local", - }), - prompt: "hello", -}) - const raiseEvent = (event: FakeEvent): import("../src/schema").LLMEvent => event.type === "finish" ? { type: "finish", reason: event.reason } @@ -84,6 +73,7 @@ const fake = Route.make({ endpoint: Endpoint.path("/chat"), framing: fakeFraming, }) +const configuredFake = fake.with({ endpoint: { baseURL: "https://fake.local" } }) const gemini = Route.make({ id: "gemini-fake", @@ -91,6 +81,17 @@ const gemini = Route.make({ endpoint: Endpoint.path("/chat"), framing: fakeFraming, }) +const configuredGemini = gemini.with({ endpoint: { baseURL: "https://fake.local" } }) + +const request = LLM.request({ + id: "req_1", + model: Model.make({ + id: "fake-model", + provider: "fake-provider", + route: configuredFake, + }), + prompt: "hello", +}) const echoLayer = dynamicResponse(({ text, respond }) => Effect.succeed( @@ -117,61 +118,47 @@ describe("llm route", () => { }), ) - it.effect("selects routes by request route", () => + it.effect("selects routes by model route value", () => Effect.gen(function* () { const llm = yield* LLMClient.Service const prepared = yield* llm.prepare( - LLM.updateRequest(request, { model: updateModel(request.model, { route: "gemini-fake" }) }), + LLM.updateRequest(request, { model: updateModel(request.model, { route: configuredGemini }) }), ) expect(prepared.route).toBe("gemini-fake") }), ) - it.effect("maps model input before building refs", () => + it.effect("builds models from configured routes", () => Effect.gen(function* () { - const mapped = Route.model( - fake, - { provider: "fake-provider", baseURL: "https://fake.local" }, - { - mapInput: (input) => { - const { region, ...rest } = input - return { ...rest, native: { region } } + const configured = fake.with({ provider: "fake-provider", endpoint: { baseURL: "https://fake.local" } }) + + expect(configured.model({ id: "fake-model" })).toMatchObject({ + provider: "fake-provider", + }) + }), + ) + + it.effect("does not register duplicate route ids globally", () => + Effect.gen(function* () { + const duplicate = Route.make({ + id: "fake", + protocol: Protocol.make({ + ...fakeProtocol, + body: { + ...fakeProtocol.body, + from: () => Effect.succeed({ body: "late-default" }), }, - }, + }), + endpoint: Endpoint.path("/chat", { baseURL: "https://fake.local" }), + framing: fakeFraming, + }) + + const prepared = yield* (yield* LLMClient.Service).prepare( + LLM.updateRequest(request, { model: updateModel(request.model, { route: duplicate }) }), ) - expect(mapped({ id: "fake-model", region: "us-east-1" }).native).toEqual({ region: "us-east-1" }) - }), - ) - - it.effect("rejects duplicate route ids", () => - Effect.gen(function* () { - expect(() => - Route.make({ - id: "fake", - protocol: Protocol.make({ - ...fakeProtocol, - body: { - ...fakeProtocol.body, - from: () => Effect.succeed({ body: "late-default" }), - }, - }), - endpoint: Endpoint.path("/chat"), - framing: fakeFraming, - }), - ).toThrow('Duplicate LLM route id "fake"') - }), - ) - - it.effect("rejects missing route", () => - Effect.gen(function* () { - const llm = yield* LLMClient.Service - const error = yield* llm - .prepare(LLM.updateRequest(request, { model: updateModel(request.model, { route: "missing" }) })) - .pipe(Effect.flip) - - expect(error.message).toContain("No LLM route") + expect(prepared.body).toEqual({ body: "late-default" }) }), ) }) diff --git a/packages/llm/test/auth-options.types.ts b/packages/llm/test/auth-options.types.ts index a44efa2274..18f9508c3c 100644 --- a/packages/llm/test/auth-options.types.ts +++ b/packages/llm/test/auth-options.types.ts @@ -2,8 +2,17 @@ import { Config } from "effect" import type { Auth } from "../src/route/auth" import type { ModelFactory } from "../src/route/auth-options" import { Auth as RuntimeAuth } from "../src/route/auth" +import * as OpenAIChat from "../src/protocols/openai-chat" +import * as AmazonBedrock from "../src/providers/amazon-bedrock" +import * as Anthropic from "../src/providers/anthropic" import * as Azure from "../src/providers/azure" +import * as Cloudflare from "../src/providers/cloudflare" +import * as GitHubCopilot from "../src/providers/github-copilot" +import * as Google from "../src/providers/google" import * as OpenAI from "../src/providers/openai" +import * as OpenAICompatible from "../src/providers/openai-compatible" +import * as OpenRouter from "../src/providers/openrouter" +import * as XAI from "../src/providers/xai" type BaseOptions = { readonly baseURL?: string @@ -19,6 +28,20 @@ declare const optionalAuthModel: ModelFactory declare const requiredAuthModel: ModelFactory const configApiKey = Config.redacted("OPENAI_API_KEY") +OpenAIChat.route.model({ id: "gpt-4.1-mini" }) + +// @ts-expect-error route model selection does not configure endpoints. +OpenAIChat.route.model({ id: "gpt-4.1-mini", baseURL: "https://gateway.example.com/v1" }) + +// @ts-expect-error route model selection does not configure query params. +OpenAIChat.route.model({ id: "gpt-4.1-mini", queryParams: { debug: "1" } }) + +// @ts-expect-error route model selection does not configure auth. +OpenAIChat.route.model({ id: "gpt-4.1-mini", auth }) + +// @ts-expect-error route model selection does not configure api keys. +OpenAIChat.route.model({ id: "gpt-4.1-mini", apiKey: "sk-test" }) + optionalAuthModel("gpt-4.1-mini") optionalAuthModel("gpt-4.1-mini", {}) optionalAuthModel("gpt-4.1-mini", { apiKey: "sk-test" }) @@ -45,56 +68,101 @@ requiredAuthModel("custom-model", {}) requiredAuthModel("custom-model", { apiKey: "key", auth }) OpenAI.responses("gpt-4.1-mini") -OpenAI.responses("gpt-4.1-mini", {}) -OpenAI.responses("gpt-4.1-mini", { apiKey: "sk-test" }) -OpenAI.responses("gpt-4.1-mini", { apiKey: configApiKey }) -OpenAI.responses("gpt-4.1-mini", { auth: RuntimeAuth.bearer("oauth-token") }) -OpenAI.responses("gpt-4.1-mini", { +OpenAI.configure({}).responses("gpt-4.1-mini") +OpenAI.configure({ apiKey: "sk-test" }).responses("gpt-4.1-mini") +OpenAI.configure({ apiKey: configApiKey }).responses("gpt-4.1-mini") +OpenAI.configure({ auth: RuntimeAuth.bearer("oauth-token") }).responses("gpt-4.1-mini") +OpenAI.configure({ auth: RuntimeAuth.headers({ authorization: "Bearer gateway" }), baseURL: "https://gateway.example.com/v1", -}) -OpenAI.responses("gpt-4.1-mini", { +}).responses("gpt-4.1-mini") +OpenAI.configure({ generation: { maxTokens: 100 }, providerOptions: { openai: { store: false } }, -}) +}).responses("gpt-4.1-mini") + +// @ts-expect-error OpenAI model selectors only accept model ids. +OpenAI.configure({ apiKey: "sk-test" }).responses("gpt-4.1-mini", {}) // @ts-expect-error apiKey only accepts string, Redacted, or Config>. -OpenAI.responses("gpt-4.1-mini", { apiKey: 123 }) +OpenAI.configure({ apiKey: 123 }) // @ts-expect-error provider helpers reject unknown top-level options. -OpenAI.responses("gpt-4.1-mini", { bogus: true }) +OpenAI.configure({ bogus: true }) // @ts-expect-error common generation options remain typed. -OpenAI.responses("gpt-4.1-mini", { generation: { maxTokens: "many" } }) +OpenAI.configure({ generation: { maxTokens: "many" } }) // @ts-expect-error provider-native options remain typed. -OpenAI.responses("gpt-4.1-mini", { providerOptions: { openai: { store: "false" } } }) +OpenAI.configure({ providerOptions: { openai: { store: "false" } } }) // @ts-expect-error auth is an override, so OpenAI rejects apiKey with auth. -OpenAI.responses("gpt-4.1-mini", { apiKey: "sk-test", auth: RuntimeAuth.bearer("oauth-token") }) +OpenAI.configure({ apiKey: "sk-test", auth: RuntimeAuth.bearer("oauth-token") }) OpenAI.chat("gpt-4.1-mini") -OpenAI.chat("gpt-4.1-mini", { apiKey: "sk-test" }) -OpenAI.chat("gpt-4.1-mini", { apiKey: configApiKey }) -OpenAI.chat("gpt-4.1-mini", { auth: RuntimeAuth.bearer("oauth-token") }) +OpenAI.configure({ apiKey: "sk-test" }).chat("gpt-4.1-mini") +OpenAI.configure({ apiKey: configApiKey }).chat("gpt-4.1-mini") +OpenAI.configure({ auth: RuntimeAuth.bearer("oauth-token") }).chat("gpt-4.1-mini") + +// @ts-expect-error OpenAI chat selectors only accept model ids. +OpenAI.configure({ apiKey: "sk-test" }).chat("gpt-4.1-mini", {}) // @ts-expect-error auth is an override, so OpenAI Chat rejects apiKey with auth. -OpenAI.chat("gpt-4.1-mini", { apiKey: "sk-test", auth: RuntimeAuth.bearer("oauth-token") }) +OpenAI.configure({ apiKey: "sk-test", auth: RuntimeAuth.bearer("oauth-token") }) // @ts-expect-error Azure requires at least one of `resourceName` or `baseURL`. -Azure.responses("deployment") -Azure.responses("deployment", { apiKey: "azure-key", resourceName: "resource" }) -Azure.responses("deployment", { apiKey: configApiKey, resourceName: "resource" }) -Azure.responses("deployment", { auth: RuntimeAuth.header("api-key", "azure-key"), resourceName: "resource" }) +Azure.configure() +Azure.configure({ apiKey: "azure-key", resourceName: "resource" }).responses("deployment") +Azure.configure({ apiKey: configApiKey, resourceName: "resource" }).responses("deployment") +Azure.configure({ auth: RuntimeAuth.header("api-key", "azure-key"), resourceName: "resource" }).responses("deployment") + +// @ts-expect-error Azure model selectors only accept deployment ids. +Azure.configure({ apiKey: "azure-key", resourceName: "resource" }).responses("deployment", {}) // @ts-expect-error auth is an override, so Azure rejects apiKey with auth. -Azure.responses("deployment", { apiKey: "azure-key", auth: RuntimeAuth.header("api-key", "override") }) +Azure.configure({ resourceName: "resource", apiKey: "azure-key", auth: RuntimeAuth.header("api-key", "override") }) -// @ts-expect-error Azure requires at least one of `resourceName` or `baseURL`. -Azure.chat("deployment") -Azure.chat("deployment", { apiKey: "azure-key", resourceName: "resource" }) -Azure.chat("deployment", { apiKey: configApiKey, resourceName: "resource" }) -Azure.chat("deployment", { auth: RuntimeAuth.header("api-key", "azure-key"), resourceName: "resource" }) +Azure.configure({ apiKey: "azure-key", resourceName: "resource" }).chat("deployment") +Azure.configure({ apiKey: configApiKey, resourceName: "resource" }).chat("deployment") +Azure.configure({ auth: RuntimeAuth.header("api-key", "azure-key"), resourceName: "resource" }).chat("deployment") + +// @ts-expect-error Azure chat model selectors only accept deployment ids. +Azure.configure({ apiKey: "azure-key", resourceName: "resource" }).chat("deployment", {}) // @ts-expect-error auth is an override, so Azure Chat rejects apiKey with auth. -Azure.chat("deployment", { apiKey: "azure-key", auth: RuntimeAuth.header("api-key", "override") }) +Azure.configure({ resourceName: "resource", apiKey: "azure-key", auth: RuntimeAuth.header("api-key", "override") }) + +Anthropic.configure({ apiKey: "anthropic-key" }).model("claude-haiku") +// @ts-expect-error Anthropic model selectors only accept model ids. +Anthropic.configure({ apiKey: "anthropic-key" }).model("claude-haiku", {}) + +Google.configure({ apiKey: "google-key" }).model("gemini-2.5-flash") +// @ts-expect-error Google model selectors only accept model ids. +Google.configure({ apiKey: "google-key" }).model("gemini-2.5-flash", {}) + +AmazonBedrock.configure({ apiKey: "bedrock-key" }).model("anthropic.claude") +// @ts-expect-error Bedrock model selectors only accept model ids. +AmazonBedrock.configure({ apiKey: "bedrock-key" }).model("anthropic.claude", {}) + +OpenRouter.configure({ apiKey: "openrouter-key" }).model("openai/gpt-4o-mini") +// @ts-expect-error OpenRouter model selectors only accept model ids. +OpenRouter.configure({ apiKey: "openrouter-key" }).model("openai/gpt-4o-mini", {}) + +XAI.configure({ apiKey: "xai-key" }).responses("grok-4") +XAI.configure({ apiKey: "xai-key" }).chat("grok-4") +// @ts-expect-error xAI Responses selectors only accept model ids. +XAI.configure({ apiKey: "xai-key" }).responses("grok-4", {}) +// @ts-expect-error xAI Chat selectors only accept model ids. +XAI.configure({ apiKey: "xai-key" }).chat("grok-4", {}) + +OpenAICompatible.deepseek.configure({ apiKey: "deepseek-key" }).model("deepseek-chat") +// @ts-expect-error OpenAI-compatible family selectors only accept model ids. +OpenAICompatible.deepseek.configure({ apiKey: "deepseek-key" }).model("deepseek-chat", {}) + +Cloudflare.CloudflareWorkersAI.configure({ accountId: "account", apiKey: "cf-key" }).model("@cf/meta/llama") +// @ts-expect-error Cloudflare Workers AI model selectors only accept model ids. +Cloudflare.CloudflareWorkersAI.configure({ accountId: "account", apiKey: "cf-key" }).model("@cf/meta/llama", {}) + +GitHubCopilot.configure({ baseURL: "https://copilot.test", apiKey: "copilot-key" }).model("gpt-4.1") +// @ts-expect-error GitHub Copilot model selectors only accept model ids. +GitHubCopilot.configure({ baseURL: "https://copilot.test", apiKey: "copilot-key" }).model("gpt-4.1", {}) diff --git a/packages/llm/test/auth.test.ts b/packages/llm/test/auth.test.ts index 6b53f4d5eb..1c7148dbbb 100644 --- a/packages/llm/test/auth.test.ts +++ b/packages/llm/test/auth.test.ts @@ -3,11 +3,13 @@ import { ConfigProvider, Effect } from "effect" import { Headers } from "effect/unstable/http" import { LLM } from "../src" import { Auth } from "../src/route/auth" +import * as OpenAIChat from "../src/protocols/openai-chat" +import { Model } from "../src/schema" import { it } from "./lib/effect" const request = LLM.request({ id: "req_auth", - model: LLM.model({ id: "fake-model", provider: "fake", route: "fake", baseURL: "https://fake.local" }), + model: Model.make({ id: "fake-model", provider: "fake", route: OpenAIChat.route }), prompt: "hello", }) diff --git a/packages/llm/test/cache-policy.test.ts b/packages/llm/test/cache-policy.test.ts index ac700b58fc..a126d9502c 100644 --- a/packages/llm/test/cache-policy.test.ts +++ b/packages/llm/test/cache-policy.test.ts @@ -1,36 +1,32 @@ import { describe, expect, test } from "bun:test" import { Effect } from "effect" import { CacheHint, LLM, Message } from "../src" -import { LLMClient } from "../src/route" +import { Auth, LLMClient } from "../src/route" +import { AmazonBedrock } from "../src/providers" import * as AnthropicMessages from "../src/protocols/anthropic-messages" -import * as BedrockConverse from "../src/protocols/bedrock-converse" import * as Gemini from "../src/protocols/gemini" import * as OpenAIChat from "../src/protocols/openai-chat" import { applyCachePolicy } from "../src/cache-policy" import { it } from "./lib/effect" -const anthropicModel = AnthropicMessages.model({ - id: "claude-sonnet-4-5", - baseURL: "https://api.anthropic.test/v1/", - headers: { "x-api-key": "test" }, -}) +const anthropicModel = AnthropicMessages.route + .with({ endpoint: { baseURL: "https://api.anthropic.test/v1/" }, auth: Auth.header("x-api-key", "test") }) + .model({ id: "claude-sonnet-4-5" }) -const bedrockModel = BedrockConverse.model({ - id: "anthropic.claude-3-5-sonnet-20241022-v2:0", +const bedrockModel = AmazonBedrock.configure({ credentials: { region: "us-east-1", accessKeyId: "fixture", secretAccessKey: "fixture" }, -}) +}).model("anthropic.claude-3-5-sonnet-20241022-v2:0") -const openaiModel = OpenAIChat.model({ - id: "gpt-4o-mini", - baseURL: "https://api.openai.test/v1/", - headers: { authorization: "Bearer test" }, -}) +const openaiModel = OpenAIChat.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") }) + .model({ id: "gpt-4o-mini" }) -const geminiModel = Gemini.model({ - id: "gemini-2.5-flash", - baseURL: "https://generativelanguage.test/v1beta/", - headers: { "x-goog-api-key": "test" }, -}) +const geminiModel = Gemini.route + .with({ + endpoint: { baseURL: "https://generativelanguage.test/v1beta/" }, + auth: Auth.header("x-goog-api-key", "test"), + }) + .model({ id: "gemini-2.5-flash" }) describe("applyCachePolicy", () => { it.effect("undefined cache resolves to 'auto' (the recommended default)", () => diff --git a/packages/llm/test/continuation-scenarios.ts b/packages/llm/test/continuation-scenarios.ts new file mode 100644 index 0000000000..93677bd71b --- /dev/null +++ b/packages/llm/test/continuation-scenarios.ts @@ -0,0 +1,104 @@ +import { LLM, Message, ToolCallPart, ToolDefinition, ToolResultPart, type ContentPart, type Model } from "../src" + +export const basicContinuation = ["system", "user-text", "assistant-text", "user-follow-up"] as const +export const toolContinuation = ["tool-call", "tool-result"] as const +export const reasoningContinuation = ["assistant-reasoning", "encrypted-reasoning"] as const +export const mediaContinuation = ["user-image"] as const +export const maximalContinuation = [ + ...basicContinuation, + ...toolContinuation, + ...reasoningContinuation, + ...mediaContinuation, +] as const + +export type ContinuationFeature = (typeof maximalContinuation)[number] + +export const nativeOpenAIResponsesContinuation = [ + ...basicContinuation, + ...toolContinuation, + "encrypted-reasoning", + ...mediaContinuation, +] as const satisfies ReadonlyArray + +export const nativeAnthropicMessagesContinuation = [ + ...basicContinuation, + ...toolContinuation, + "assistant-reasoning", + ...mediaContinuation, +] as const satisfies ReadonlyArray + +export const continuationTool = ToolDefinition.make({ + name: "get_weather", + description: "Get current weather for a city.", + inputSchema: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + additionalProperties: false, + }, +}) + +export function continuationRequest(input: { + readonly id: string + readonly model: Model + readonly features: ReadonlyArray + readonly image?: string +}) { + const features = new Set(input.features) + const messages = [] + const firstUser: ContentPart[] = [] + const firstAssistant: ContentPart[] = [] + + if (features.has("user-text")) firstUser.push({ type: "text", text: "What is shown here?" }) + if (features.has("user-image")) + firstUser.push({ type: "media", mediaType: "image/png", data: input.image ?? "AAECAw==" }) + if (firstUser.length > 0) messages.push(Message.user(firstUser)) + + if (features.has("assistant-reasoning")) + firstAssistant.push({ + type: "reasoning", + text: "I inspected the previous turn.", + providerMetadata: { anthropic: { signature: "sig_continuation_1" } }, + }) + if (features.has("encrypted-reasoning")) + firstAssistant.push({ + type: "reasoning", + text: "I inspected the previous turn.", + providerMetadata: { + openai: { + itemId: "rs_continuation_1", + reasoningEncryptedContent: "encrypted-continuation-state", + }, + }, + }) + if (features.has("assistant-text")) firstAssistant.push({ type: "text", text: "It shows a small test image." }) + if (firstAssistant.length > 0) messages.push(Message.assistant(firstAssistant)) + + if (features.has("tool-call")) { + messages.push(Message.user("Check the weather in Paris before continuing.")) + messages.push( + Message.assistant([ToolCallPart.make({ id: "call_weather_1", name: "get_weather", input: { city: "Paris" } })]), + ) + } + if (features.has("tool-result")) { + messages.push( + Message.tool(ToolResultPart.make({ id: "call_weather_1", name: "get_weather", result: { temperature: 22 } })), + ) + if (features.has("assistant-text")) messages.push(Message.assistant("Paris is 22 degrees.")) + } + if (features.has("user-follow-up")) + messages.push(Message.user("Continue from this conversation in one short sentence.")) + + return LLM.request({ + id: input.id, + model: input.model, + system: features.has("system") ? "You are concise. Continue from the provided history." : undefined, + messages, + tools: features.has("tool-call") ? [continuationTool] : [], + cache: "none", + providerOptions: features.has("encrypted-reasoning") + ? { openai: { store: false, includeEncryptedReasoning: true, reasoningSummary: "auto" } } + : undefined, + generation: { maxTokens: 80, temperature: 0 }, + }) +} diff --git a/packages/llm/test/endpoint.test.ts b/packages/llm/test/endpoint.test.ts index 43d2e1c5c4..504c9843c1 100644 --- a/packages/llm/test/endpoint.test.ts +++ b/packages/llm/test/endpoint.test.ts @@ -1,37 +1,40 @@ import { describe, expect, test } from "bun:test" import { LLM } from "../src" +import * as OpenAIChat from "../src/protocols/openai-chat" import { Endpoint } from "../src/route" +import { Model } from "../src/schema" -const request = (input: { readonly baseURL: string; readonly queryParams?: Record }) => +const request = () => LLM.request({ - model: LLM.model({ + model: Model.make({ id: "model-1", provider: "test", - route: "test-route", - baseURL: input.baseURL, - queryParams: input.queryParams, + route: OpenAIChat.route, }), prompt: "hello", }) describe("Endpoint", () => { test("appends a static path to the model's baseURL", () => { - const url = Endpoint.render(Endpoint.path("/chat"), { - request: request({ baseURL: "https://api.example.test/v1/" }), + const url = Endpoint.render(Endpoint.path("/chat", { baseURL: "https://api.example.test/v1/" }), { + request: request(), body: {}, }) expect(url.toString()).toBe("https://api.example.test/v1/chat") }) - test("model query params are appended to the rendered URL", () => { - const url = Endpoint.render(Endpoint.path("/chat?alt=sse"), { - request: request({ + test("endpoint query params are appended to the rendered URL", () => { + const url = Endpoint.render( + Endpoint.path("/chat?alt=sse", { baseURL: "https://custom.example.test/root/", - queryParams: { "api-version": "2026-01-01", alt: "json" }, + query: { "api-version": "2026-01-01", alt: "json" }, }), - body: {}, - }) + { + request: request(), + body: {}, + }, + ) expect(url.toString()).toBe("https://custom.example.test/root/chat?alt=json&api-version=2026-01-01") }) @@ -40,9 +43,10 @@ describe("Endpoint", () => { const url = Endpoint.render( Endpoint.path<{ readonly modelId: string }>( ({ body }) => `/model/${encodeURIComponent(body.modelId)}/converse-stream`, + { baseURL: "https://bedrock-runtime.us-east-1.amazonaws.com" }, ), { - request: request({ baseURL: "https://bedrock-runtime.us-east-1.amazonaws.com" }), + request: request(), body: { modelId: "us.amazon.nova-micro-v1:0" }, }, ) diff --git a/packages/llm/test/executor.test.ts b/packages/llm/test/executor.test.ts index b294606ff3..fb8a467078 100644 --- a/packages/llm/test/executor.test.ts +++ b/packages/llm/test/executor.test.ts @@ -106,8 +106,8 @@ describe("RequestExecutor", () => { expect(errorHttp(error)?.body).toBe("rate limited") }).pipe( Effect.provide( - responsesLayer([ - ...Array.from( + responsesLayer( + Array.from( { length: 3 }, () => new Response("rate limited", { @@ -115,7 +115,7 @@ describe("RequestExecutor", () => { headers: { "retry-after-ms": "0", "x-request-id": "req_123", "x-api-key": "secret" }, }), ), - ]), + ), ), ), ) @@ -388,7 +388,9 @@ describe("RequestExecutor", () => { it.effect("does not retry after a successful response reaches stream parsing", () => Effect.gen(function* () { const attempts = yield* Ref.make(0) - const model = OpenAIChat.model({ id: "gpt-4o-mini", baseURL: "https://api.openai.test/v1" }) + const model = OpenAIChat.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1" } }) + .model({ id: "gpt-4o-mini" }) const error = yield* LLMClient.generate(LLM.request({ model, prompt: "Say hello." })).pipe( Effect.provide( dynamicResponse((input) => diff --git a/packages/llm/test/exports.test.ts b/packages/llm/test/exports.test.ts index 237dadb27d..693a21638b 100644 --- a/packages/llm/test/exports.test.ts +++ b/packages/llm/test/exports.test.ts @@ -2,7 +2,14 @@ import { describe, expect, test } from "bun:test" import { LLM, LLMClient, Provider } from "@opencode-ai/llm" import { Route, Protocol } from "@opencode-ai/llm/route" import { Provider as ProviderSubpath } from "@opencode-ai/llm/provider" -import { Cloudflare, OpenAI, OpenAICompatible, OpenRouter, XAI } from "@opencode-ai/llm/providers" +import { + CloudflareAIGateway, + CloudflareWorkersAI, + OpenAI, + OpenAICompatible, + OpenRouter, + XAI, +} from "@opencode-ai/llm/providers" import * as GitHubCopilot from "@opencode-ai/llm/providers/github-copilot" import { OpenAIChat, OpenAICompatibleChat, OpenAIResponses } from "@opencode-ai/llm/protocols" import * as AnthropicMessages from "@opencode-ai/llm/protocols/anthropic-messages" @@ -24,26 +31,25 @@ describe("public exports", () => { test("provider barrels expose user-facing facades", () => { expect(OpenAI.model).toBeFunction() expect(OpenAI.provider.model).toBe(OpenAI.model) - expect(OpenAI.apis.responses).toBe(OpenAI.responses) - expect(OpenAI.apis.responsesWebSocket).toBe(OpenAI.responsesWebSocket) + expect(OpenAI.provider.responses).toBe(OpenAI.responses) + expect(OpenAI.provider.responsesWebSocket).toBe(OpenAI.responsesWebSocket) + expect(OpenAI.configure({ apiKey: "fixture" }).responses).toBeFunction() expect(OpenAICompatible.deepseek.model).toBeFunction() - expect(Cloudflare.model).toBeFunction() - expect(Cloudflare.provider.model).toBe(Cloudflare.model) - expect(Cloudflare.aiGateway).toBeFunction() - expect(Cloudflare.workersAI).toBeFunction() + expect(CloudflareAIGateway.configure).toBeFunction() + expect(CloudflareAIGateway.configure({ accountId: "fixture", gatewayApiKey: "fixture" }).model).toBeFunction() + expect(CloudflareWorkersAI.configure).toBeFunction() + expect(CloudflareWorkersAI.configure({ accountId: "fixture", apiKey: "fixture" }).model).toBeFunction() expect(OpenRouter.model).toBeFunction() expect(OpenRouter.provider.model).toBe(OpenRouter.model) expect(XAI.model).toBeFunction() expect(XAI.provider.model).toBe(XAI.model) - expect(XAI.apis.responses).toBe(XAI.responses) - expect(XAI.apis.chat).toBe(XAI.chat) - expect(XAI.responses("grok-4.3", { apiKey: "fixture" })).toMatchObject({ - route: "openai-responses", - }) - expect(XAI.chat("grok-4.3", { apiKey: "fixture" })).toMatchObject({ - route: "openai-compatible-chat", - }) - expect(GitHubCopilot.model).toBeFunction() + expect(XAI.provider.responses).toBe(XAI.responses) + expect(XAI.provider.chat).toBe(XAI.chat) + expect(XAI.configure({ apiKey: "fixture" }).responses("grok-4.3").route.id).toBe("openai-responses") + expect(XAI.configure({ apiKey: "fixture" }).chat("grok-4.3").route.id).toBe("openai-compatible-chat") + expect( + GitHubCopilot.configure({ baseURL: "https://api.githubcopilot.test", apiKey: "fixture" }).model, + ).toBeFunction() }) test("protocol barrels expose supported low-level routes", () => { diff --git a/packages/llm/test/fixtures/media/restroom.png b/packages/llm/test/fixtures/media/restroom.png new file mode 100644 index 0000000000000000000000000000000000000000..52ed88afb0f06e915ede727b751fa5ea0d98ceb8 GIT binary patch literal 14496 zcmeIYWmH|u@-K>OaCdhn_`*HGgS#%=f-Ee!L$DACZoxIUyCt}@fZ*=#c31Y<=bZh& zW8C-gy$|osF?v?duIj2^Rd>(XG9y)$<Qe}IC50YUOnNC=QSLpov& zq=3mrL&r@=Nm0n$$${O}!pRKC?&;tR;X^?Qi+MVmn%e>0D9wOYHjX0Hr>&jTlr|P3 z)Y`mCoJ!78Kx-R$Zx^7tx3Y%0x1G751+|zcim;~;M1cd)&6Lv9!QRnT$Ww&+FTFyL z{GVbDYRbPv-0VcCb(B;orJP)Vlzi-*?3~o1D3ro37M4OEq-FoE40#fvwsv!K7UJOW z@bF;wc+2kOV#UEFC@9Fm$<4vd%?6QRbMF{aB%&Xr}O{7`!7q=(FS6fo0{WK$T|LwIi&G8{?mGp zhyS!c&=Jz;E|Au>UB)hiff&T+V-JLal8;RKhN!BpOE7rq!;u-1 zj0w$@d%FT7kDLpy8jsE=iA{+qsVLE1$y&Llr;62GlUGKK!dHrh)!)E)(?J;>QNxaJ zU;GJ!u;;|@(s%Wf)y~-csMqexX|uR>kpdP&UR!;eP;=D$haEKzSF>NWr`J#|grRa6zpCGJ8}SV>Km|an zP$$6#W7`zx1kisJ7?-nKk zcm)CT2*=1h)|%@XI|oX*Ztjad;(^blbp7*1q_H zv?=i#wXgi0l5SoNUk4?pH8+EDDn|k$AZX$KN-Wu=Or0AxxAXtkd5<=maARh(1bw*t2qJRtJ#6&iez)nH+q=dDAWzvDd55~*E#0^F> zL1jd2?IL%EB1IS!hZTSy3yfZ4Zh}4ukjp{63eq;g`~=mD3Aav#A|2{RDfRPBO<)EU z{T3>`1ePk#SGWT4{dmF;;?cR9s$3c{Nm8x3%zKP8aGAmEQkfI5#UuyeE0V@0aP+-A zIuv~2WG3_@LA~obp6D6qk;u3tk1*+b zWT_J@Xwed=6%wfPaZ99a<1O>annT^FV1HV@L6_?1F!p zIpA_g(NA$4q1*u^2hH{_nza8QwWsDIYlYH}VCz5WoipVyIW_UArf?P@C9?{=>xG^JRXhsGO=Ci0UR`A3nD9M!3wnP3G{dYgDwdC`2G5A-(h zC7(5A`csC-{6qPb+OpJSMBSmrDD7>zE)AkUy+^<6o549DO-ZfV zrkdvNB9VWE*nF|9S;(KYn3$PxYuPuOww(^Qlzv;N8@8ZT3#yIV!QVmNDH|mjG1jrx zcV@j{D`g|s|G@gpx~s3Hx6;s~%T-ZR4$@iv5mvEW{os2KDK}TOj zzuKYTSOic*Hq1U>xmdZB$o0;K}UC&=TSW zw7WNeb_BHrRzbNUcYb-iPoA&F2C+tad>bv&vR9YwI8?Dwqba8rdV<*aXOsVkyDscRE|4l zvm1vwMV*d!82ZWj8Faqyw0fa``Sj}h;>*gSMSqBS=pJAmz>~wiMza*%9CzDM5$h6Q8{?Ar96j_ykD;*bN8>5vU0(IXYGtLXRXkrRm%&wri& zdi)Y@2|v2XUFOlSbkwupv8ywpE3kWEu-u&2T(nyEzc)6$5@m* zI>j4Wuz@J!QR(C;b5aCnqegKYQf zq+nudrl4Y2F&U5b(2%_5sS9N)svNJg(#=4(=Hj_DL~|7W0e%?O+YjkJw?(yHRnOC@ z{`SC7%*+q>1zbG<9BtrTjlPr7jv|Xzi0-W1u4unVoK^vf#gr@P&sVSbK98X_p>3df z@IN>RtLCYFF`lZmc_@4s{X8m@zUq|Pxb0G6w_jP2UlCPd2*d)$EGafRfN$!BzdtF< zh|3&<+K=rT{C{_^esnE*9ZNHOXpQplz1O|Fd|sw%J!BbWQMg^Z**fv+;P-QS8gIC`Sz?Qo9eEd6n7 zd-CgdkGN0@JCQMABiEjzz8fK1Lp2eNY;7@c{N%)J$_#h`cW!3!XxYGH>SgOiUABl> z*)G$_Kg_LgZRF>|Q>_%+m*ha#{atUp-Fi`>Y|j_a(nv!r>N)|t;hPT6j?7uVn=j)9 z>fhQSGYeBAo2CQ5`j@n&`WEA5zluZW)8fvPkL~ASyD>XsHknqA56i+HEN655OBqYr zrz1_%Ui>E~&px%M?#sKY{^#OXYooot!+YbB#Rf##z4Ko3uS!;?hgQq|%8p%5g_g;{ zzQ?*FwQ?eDS=yb$ey@xAXBii5b>ly(4ni-Z)t|ec`HjZB7areV*m~xiVZ?|vbT)kQ z-B5WIt3snkzv)QmAo6Ox$sB8aJ~dozM3+Gmd5(WJy)&O=$W%cTeJj@J|L$&zzio}> z#cqMW%xQGBw^NM#7dcUabHVRwEhq`ZjAVqarDrJBFHkvoB5*cyo^c|U6L-L=N&H`?yu9Z1qZ87olu*(7)&dBIrxy(O%zb)ou!fz6f-1`1O*383r!cScD1Lm>%adet@h3PQ8r zNlR#WLLdD$woU?)BA)HCIw!s~p-ADc*R?UlN0qa;=}KG?FeAaiKAKyug(723&RX*u zvF7F!<9X&9&M8UaPR2+hnZ~PP;u3v`Z!&i*Q*vBeVa634vM?31(vVQ~L6AzRjXw6D$Cle^tr-y{#kEeYEsz)1E_LBb!3ndP8 zKYLkA1S>lOENZlz?p6c>C=Rmy{hw9W=l`t}1O$s?VBp z;N$NZd$@XEowLoxY;Iajy(BbFUyZz0>_tOHRVMY?+gt&r{z`DsY;BaGjN{r1;&gPY zQOU>O=Oc;xRntXwb5ZDXH&qHgx4x>iz|#r4{k=vx+c{EPRN$w4qgIE z%F1))f{;jcx!|9rs%FHRX&+4===N7q7lC>GLbR@L3SZnCc~&@Gcb=ME_rbTTcqcYD z`DXLwUwz?_Sgjzj6d?N#4&`dQC!}TH)1A8A+3o=nW~&uq^7qCRFSgyjs1B+}_}DI4 zP=U&rsz*`kAC97Y^+d|Rnp-c%M}>v-(_>cI?{RQ8m6l|msT>=?F>RNY4;Rr=N~Z)G?y+5TSP>7Y6YRqMm4;vH=hcpw$!j|uj}BW) zO5X}yB4YSI`Q>^49*I85%Bu5w4oj=(BzvWciHVsluirFjcrx&sot;(i1?_D{duP`_ zA5Itg@M%|hJk4iMCpe*xldbv<7S=r%h|IbY7#Y;sYU)+zJ@%N|YFD@3v>Z;S@%qjl zj&^4w$1iUli5r~Q@00GQj%3uf$qOkN90g4wkuQx zU9I>e#o}UNs{Sy6#ln&h7yr5hR;rn@+he%cGXAeEfm{ zz+0cCA}8a=Z}wX~+paTyGn;;bOzOZZg~X618A`i`BOb>gz>bUxshH$4fUl_Y^<_yB z)uTwW^+aR8x@dHoK91!5VW*xQ`OQ zgU*hRSj;_8?fCj|zQpg?ipCeYLRn)V77vnO!&ump@sE3rVqcz;2ekw6jO%;OfL)3c)WG8a~M#o zFGCp{1RmzF8|7@K3k%A$tEM_%7h_L18o1aiwHlsaXX8VnVF%G3mRr3*S;^~S zt7yanSO7R3k}Ua9P^dsKHeFSu@}W}res6X@oygr_tB(Dcc(Op@ThJU4ve`Et8}6ZW z4*xE@=lfj>w}Y+70HB6tR@*(3ZjFUoaQ!#AIC8CD1AO{786mq+E`ymK=k3`!#y3YO zhje6Uq%jE1cNh*sW4D$JyJMNT3IrT!x{a%T01?e*W;`anp015b)`h)g_}abag2p;S zONsPM!0E_{uV(y*!uK*n+!lGYRw~nzG~sv6PrUYKDPOWXpWsnGB(pw!zI=<^?7Z&L z^3%WQ&ckD)k1HJ?%&?wiJLf2_S=MQfzc<+&+U&F}I4~ZX2?DS?D`p7`ZVzRCyV&87 z*1hBZ^wQ}1c^!IF_xUnTtXv6gU%&a6jNV==MFm zD1pn-9@fAX$NOw5*d(S~D8o)rjQVRq#i|qclv<%lF11Fnvs%lieVFB@kHH}O)eB?6 zEm;*umDDe1q9JR~S0v^L-H%1!_JTW+)L{S1U;BIO&u%8KMnbQTPO^SEuV<`QKU01+ z{5&_8+pp@ZO!s1ZbW5_;$T2bXvpg-V+n-YJ%sSq;^7GK4OIwAzay9bnTwnGdBuj0M z@t?fE?40bs?3`Ygdc41NU0KY?8Fb7ZWYw)9_FR+nBv@-!4YDekSe8LPe!0!||9o?@ z^q6>VP|7WNgo~Z9Oiyga?{QAtgGi~d@Oa67@NC%{&_Af0rLa)5i=tDg98(0-VNk*F zt@Tu*RO>rBUPnM5H7>440GYt{07<{tc-{s}WAiYxjG< zt(T!~1s?MQoyEG3nWa4-5+zax4nkS8)Ec~E{VJ*kt8(vGLp=efmV{f?{=s6$=N&hz z9ad4Gm~L&5Wv56tgOXVBnYfJYOdA<+#4{Rh&kH=bX7W@V_@wsSpSJDsrowXDs_gQu z(b5y;9o|MrZD&>6W>)d3iID3rp;>rCQ|(F7vy+6cBF#_xNw=q@(Y1Wj`Um&S(lGaRyNq_ z8b>S5%V|K;PJ<%oSMCzS zz%Jr*b?EAH?wc!`YvG2C-Kwe0aYBcKg@OW!a`htR-jvx~=J9#Trxo|WAhYcYnJaP@ z+6hZ4kdRQq5`o!n0PquL>pV$)o>f`L)&%wImK5UcWO`->FV2GNR(?nDfMBfRvmI?^ zl^~f=(<=Kg$LMe$dW?fsCxV?!japm>4H5?lL-%l@{v*BH)1BH9_2j_hO`a(&0yV8Z zpHqGbPMBKJ32d?T`Im-zAuNEk=pnClH^l^j!}v6g(@LAfrIkuSoOWjw!{br#C)1WX z#pXxfDOj?rqp6`}&LC^y=S~8c%!8EM>y~lrDII@mQZ`c8?J=oiz%3WgW^Bv@$0n{F zvmDy-@f~X(q4TFmWFpag*(>8vW@A9Tjp*PsLtGxmTqTy-Zt(jpbZoTh z!&!e?6&hUBh>Xff)KD-Q#U&rGUNLarea)=i_!IXUuO@vRlLO%TL-+vxw2akw2DPG0 zp>ondN?Ls^ID-`btcOC-kA8b3X})L-wY)`ay!4SaBRg{Te*f*AP_N0?)fSt~_`1&t zlpw;GgILPaYN1#k(5Xp`p*mrzEZ~| zy%0mvVOB8>b@U)_u(s#gtwZ{i*)Ud!`=ffEIpXL%QC1I!QQqevzJ?SKU_hOLfWs)q ziT{($A>(wu3}RM8d%?8^!)EGJW|7BR%a%k=nL<>a!OSH-x2F_Q^=)|DnGtQ&Sd2+Q zM~cD@&i>F{34SMMYS1-FVP7>2u zMyVx%VkhlqTvrOdq49IYFzo01g$DOpQ~Cfa1A;a&<%=~8^(>ZeY@BuK-l8`&_e$cv z$E{a|h~(b5t%W&co##&R##2u(V-{E82URA0>{H|4m5*{FS%!o8WDd@;S z(JH}PLxiahpX&uEzdj5T^MQUeBhy2=hw}X1q!nQjtKrJe*inu0`V|#Xy>|-uBRr(= z@rdIarivp;y+}NCWGmJtA~72i~%NivD9*Wy!R=cbd>3FrA+W<9t9L+`6R_B+ctNpa3 zfx71ReQ$M}C;MBR& z>G(C(ye&$V#M`6AMXN4LI#7`^c~M|HfGEF`zZ3A4jN_oo2O;ai+I30Usam&}Ms_x# zN3VX`(N6A2IZNO@P59LXk+krcDqWCvi|8}K!5iu6WU~EVR%Qq&rDTLZKec%aI=p~H z)|ZjFi7NYU(gPk-xL$oP{m$4@gdLHde{2INE=j(!=(eyXRjDSt|H^FlW+ZcwaDP{g z0rbG@zgVAH==v2-rtLhd|Fjco$%ffx@&~=hZHCwm^XjNpn;G5j$or>0hU)a%J*h;C zHM-xyML9=s6dmX4t6W7$CaW`*+iU=$_NU8PTcT-eW{0~j^03h_LUWBjGHn*GeK|*f=-Tz&=qFBRvI*Kc%=W33&Q{KYbD#GHpWTc z-P+OAAC;}{%YALp#DS*5Y;LnsB0U-!naJ`d6-skXyDC2mwq$IU>goFLY%6<`aU%C( znqSk}v_|c3rSK^De`XGau(9y?PGSSh=4;M}8uf-Mj`MM1Kj!@H zf5z%76GXCA2Y;WBSDPNO{l=c9ps=vR(|{ebI~fc1eO>0~akTKKkVC0!HY;G*i$NC| z-MRIuMN8r!c+1H1mih-xpK?UzJz+mVHLR|FlYNB^2ack?faR3IP}XMhG=eD4v0l65 zO7LRIuN!_|yLs(!VYoMj_FN52D1|DFK^WgN_o5>$G zByU&ub<^ujk_6e%PY1M=jJSBjcOuzA8$saEX!Cm%j1Rl~h-n_YpHx-m8tl2_DgeQ9 zihR7p6JtE3k3scFXk@%e7u8nueafgs**W0>5-mw^dXbrqd@vVC*d@~AENV4xu8#=b zCZXwT0T2n?E0-#gzzz#fY<7n$H5K^8qc*kQ(qNGUQrwRxW*W+~tm!~FgKsuG)(E^4 zbWR78!P~>e6O_9LJ#>AKzP6g88!y{7QY@p`e!vJ zfC{t|jBDJ7jz;)P4l7JETv~A6a_Dbo0D##eO@(@k=oFUzl2+P2@+)(rBHo`q@xH!$oDM7$$q+`uhJp9 zMU)C5Xx45P_YKKUqafkXJ=(boWl**dlZ4@qz%+il5AxG5%JW+LA0>`@`qk!p);)g5 zM=tU56~m!AJpQm1=b&U3Wq{L~%gVblFvpM0FzcvTNsh*W=PB*hwkGLp=m zYpJf-YDZ)!EB34@G-njesKRzb&G|h+t89;>Gm$0Ps zo7{nkN(I9ZbR#m6<)l6O29$%}ibiH;<_eLL#gdBl4NNe7ZqmOO&`L_1QyUFKB-2>c zk~k_rCVh}1nx&@T2!nm}v+TXFE2p=5ByU*g-J>9uqKojKt>~>t0Wpu-9J-s`(k*>a z+MGaA#zv`*MkUQ$Bv^85>>GP;X&UXZHQ_h7ldtrx+sXv$aiZUT+!~K%g_+_ehVv*~ zj!aUskN&QVAkxqm|AF;Dg~ z_$A_eik#Dp8u-eAS)@{cju_zs-}uq6tcalgQgY_9;_=S(=5#jU*Or7`@^STihJV-N!y&Y9`0XWmHmg<$09wrG|0Q`-uqw{qf*lnF=Aa&rG7e zoVnk6yh>1M{eI|w2(D+OI##wJf;6&||pjDN+yEL#sYupLYwF;*-YP=VHD zZ>-U2e+>4em{25m$|K_8@PAJ~F7-Vdk5GawtUMtyO{Kf_x zel=-w2td3z+TSEo2`=I?`?0KEo*yT>;N7zrr+uz*{58G~%ZL{Aj1b4Gb=T#aDe9iF z*cesqRlmX#TM_nZDA+)qch6G2*Z@Cmu-+CqO_0X5SFQk0uVIGxCX2PC1y`ld-dRjK}W2)r0}!-$yhm5J-N|KMfO5fw7Se&Sh#D zBuXY+Y}wZDRfaqNj>&k%6HeRpL6p)wH%ip@^=W$6Em(>+f9+1M7(+q%*feCl4oGvwAzMLdB1vuqp`eGsn`Mmfo-M zb-Qy));hhsjpwVTBw9e3{|F6UP%m4o_Zx13XrA3O^gy`oUs(ADk+Vy1&B-2Z2A+CiyiSJ=B1Tt_7i&N!(se?>G zu6)9F(ADdzTr;FaR7H7~k;WX8AS1QdI3g1d=tPQIJ^et{5lPmTQ&?U77T+?A$F9p1 zt`7cpePLKzSvZ^XLwC4As#5o_r*&1eYnpeY?GQ&|zN6JuE4wJjyKI|{Vj?nVZQ!aa zZOgf!j-Qs)Ca0uDsMb5p{oq0JBTko@y!QFy%=j8^fd$H-y8htD*(10z&(CHKq;rB{ zN2{&j$Lmkp-%^AgMO;JS!N>0F`+C0X?(L3tglW0Ytt8NenyHYn7)v3dn7Pys7pQ$3 z%;wC~lj$sOAYVN0C`k(%K)diK#6%;(*>pfz((tU&rz0N!jtO8HS`olEE4r5YgacT{ zK^v9)P3`$(~4IgZX%4-s%oEIAN!&}SkSv- z;BRbfYcq!NPv6=L&6Crmx+a}Eb$7ubFz}~*_(0?K0};7hlD=w5@ndnLs$Q>!x=zL?OpgFpF;8pE)5Ap1`>~m;dq)BN@5>Deho67~tLPMFg{`R#~(-+Sp1=`!g}FUVp@W`P9q{;Kms z3I|KHCP(_KYL#f!vUj&Cy|eO5JuoW!;q-WY#guehTVLt2mS`i`h3Iry=(HDnOE9Sm z8gIn07AqXpeGl2YtsTC3r@j)QlS0%TdCm8TTSsa#+D}|>wqe{|i$A&OZvhaW39PrJ z*hacZBKH~4d9Xjc?T{V!WGXOat(f|L>g?(ufvE?M*>gz}`$FJ3s$aHe*DpIXz|QVm zw<0Gn=-e{-P0hP$Dp4btAW}PM@{uUq>V$U5e(}0Kvli*7dCvDGVcjISJ`9T%fM|D1 z?%P(=jDHMe^u_je?D$|xR3GfKZhpOaLt#D5Z(L*EB|)x}!5g$h-EPv|qjB9YBswMq z*+}8p;CRrma5b6Lqr4%8QFq!p6hB1s>1ZQmFYXCWvPSg5%rh#JhLwBH3_2v+^m*~T zMp=9uW;cR462@z3WlS>hVZy_Q2mUb7+HHt&IJU0-OrrI50&UL}raIajh8+A_n=8U$ zuw~S{31CQsp##O@Bd3C?;4lhF8b395>(FD~bm#!?l3HRE?KuM+mbZYN&@4ZOvuGHW z2VTE+b-x)CelN7Z$`K(Pg7>jTF7}Ea+BXJ>!9{uJH;sU9S0C6(#&GBBKNrCk(d~k4 z6pNmT4F#%+Tr$>L@2$J*IR9SNYE1C5MtIHBJ^lIIb zw|Dem&K78JrP)CQ=*bs>9tOoh1f!7MvtRF1X6}*5mmu3PZ;MObW7PGxW00K{VgWc* z1-DH1sml#h>ESM{4PUVpey^EV4KAXBM3P?d28+{ealW$?_o2^!=8HY(=vmf7JLnbZ zgq$g$p;cZB3r9=IDsyQI{@4MKA<}?!@>iHClZDhKFEclI4uCT+>FwdfvfBq>n`k`R zANE=7lRa3|i@kz(o&w`{d#1jg6AcnhS>t}`u_9<_1uA9%uzkgcD6fhs@ylsgSa zU`$L*@EA_*?b^f-y#iw;vV1_1x(`YmB>PT5)R1N3OvkhnLI}YS9K!_>WaSu1 zMNv@x@l2m~;z;RRSu@Cw3rZbV>O#U1^p!!gmZKW|dL3d&t%8?fMRpJ*I z%>o z{Tgpb^fyMF{AB%wiE=Zn`|tL!K!%p^Lc=56nb0UzCLt1ArN1hQT7N zn!q_rY=7n&TEDE$@CKD|2=*3MNvU?u5a}8LC&g7Uo2O^OR(JT%RH3!G=N7kdC3gJ0 zFy;{L!jYhfU{MY3FeV0$8kF!t54nRJ!V%9PJ;EM#?r@vtUKpi%I^lY(1GDw@0fveo zXW>JQ^~)Q*=1&PiS4(;h!%rvzv^v2dLb$GqVbAK2CDbKxkR-F?OAUup_Jxy9>Oy5vDL528bn7{g%4$rPck6a~3q;2#DO29=RB&d>WE?ao z$gSqYm2=znum<;0i)565S-x=)8AX7mzs%VQkjcTw6}4neeH`UV+_^VB(J)dOtn;cx z;J61H?%#vujH&(bB|mmuj+J@^t-l2N`goRn*9?g(Nu&}x=%L(rL8K^n^lEN>YTJm! zR!lXGQ9(Kz+&Dz4HY2E!$lR=h-}kzo9T*sby{pjK=0`sbCXCm5Y_;A@5xg|Cf1Hht z!e=qH9?#WPo8ILt13wOvr}4W|hf@gIIn-=&@u=*5v;WPp$DqmZuqLpy?l)$Mw@1J* zIsaak(gN;9^Fvxucxx>JF1GbMt~bo38#Zt+LYr&UXDx|6X^OTiI|&%_5&koUr^dXqd?@253CJ}T8%-lpUOyQA-&^Oqu3 zIt^WOemKB#?2=t9mV!0GkPwobCjD@Fjq`OvA2mCYWzu22>KZLpj^@Nb?^_Co%2^bj z+E{yYELOedbj0!FW)Mtr(IVL(doSNMw(ta=Kk)ao`23}i~Aw`P^^0v zW~;RF5oC)=AttSXxBcvlw&K;6O^MvYu8#PSfhCH;Y_ZtAmHcaXj9n63^g!j%fxB^6vp+?6a}}o)V!)U=$JgRop&DHCx)U&(C}Aou*5-qpz7Qvav8px4AIk zHt?aTKp&$$42+Z_4BaM_dHNjtnuz>DexfkJ_@ST7^NtnS{rIdy)1WDz#VSa*z0Z!R ziW#8_S9!*%Bj#z6t@6>6C+N*eDMxCy!&ep4VQ8LYq(b6!CO!pC&0ReWv-O%DtbC33TC-#I&|&4KE&Y~a#(nvK|5K18XH+Tyd5SI2AQSDxy!?))AX?i znb>O5>6sy_ltRu_^U0PvieilYv8vRoaxnpljae2k8woVwpH1?0r0`d4m9am^2aNOx z!iCNG_^-$SJnYx;*kT1VzgbVi4@xgxyKIt6bhY%6Ndh28$-ikT5-pn~#3M3Et}@2m zX+i$WP0FJP$+v*Fz|s_8*b}!%MnF!djx1`lopFm>w=-&7VYHusY8O!+rCd(u$4#de zug$`08N$F}(xA?JMNJxJO<}MOab+qfx?V$gbQ6fnrLd%)m-i~&b><85NY2)o8i^23771die;N9hJs$|L=0R24e`u2E!ht}z zl;)SG`Hyx8Z09&g)87)lNBbu(PZ&s-&e}t;3Hhg~6G$K2C6_As-vCnfjo~a)#{3Uc zA~2Fizs(tW|MLCs5Ue3XKzZen$$!S;7J}b3 zE_dc{eg7g1m=I8rj`6bp!xT9L{|VPu;(vO21_uEpJc%}i^iNa2X(0GT!ahL$Dfw>z z|8G$LUkoZ__!;w8s@Dc?KUc } -const model = OpenAIChat.model({ - id: "gpt-4o-mini", - baseURL: "https://api.openai.test/v1/", - headers: { authorization: "Bearer test" }, -}) +const model = OpenAIChat.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") }) + .model({ id: "gpt-4o-mini" }) const Json = Schema.fromJsonString(Schema.Unknown) const decodeJson = Schema.decodeUnknownSync(Json) diff --git a/packages/llm/test/lib/http.ts b/packages/llm/test/lib/http.ts index cfe7e6883b..f6c600555b 100644 --- a/packages/llm/test/lib/http.ts +++ b/packages/llm/test/lib/http.ts @@ -1,8 +1,9 @@ import { Effect, Layer, Ref } from "effect" import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" -import { LLMClient, RequestExecutor } from "../../src/route" +import { LLMClient, RequestExecutor, WebSocketExecutor } from "../../src/route" import type { Service as LLMClientService } from "../../src/route/client" import type { Service as RequestExecutorService } from "../../src/route/executor" +import type { Service as WebSocketExecutorService } from "../../src/route/transport/websocket" export type HandlerInput = { readonly request: HttpClientRequest.HttpClientRequest @@ -31,12 +32,13 @@ const handlerLayer = (handler: Handler): Layer.Layer => ), ) -export type RuntimeEnv = RequestExecutorService | LLMClientService +export type RuntimeEnv = RequestExecutorService | WebSocketExecutorService | LLMClientService export const runtimeLayer = (layer: Layer.Layer): Layer.Layer => { const requestExecutorLayer = RequestExecutor.layer.pipe(Layer.provide(layer)) - const llmClientLayer = LLMClient.layer.pipe(Layer.provide(requestExecutorLayer)) - return Layer.mergeAll(requestExecutorLayer, llmClientLayer) + const deps = Layer.mergeAll(requestExecutorLayer, WebSocketExecutor.layer) + const llmClientLayer = LLMClient.layer.pipe(Layer.provide(deps)) + return Layer.mergeAll(deps, llmClientLayer) } const SSE_HEADERS = { "content-type": "text/event-stream" } as const diff --git a/packages/llm/test/lib/tool-runtime.ts b/packages/llm/test/lib/tool-runtime.ts index a12941603a..5c98b78435 100644 --- a/packages/llm/test/lib/tool-runtime.ts +++ b/packages/llm/test/lib/tool-runtime.ts @@ -1,4 +1,3 @@ -import { Stream } from "effect" import { LLMClient } from "../../src/route" import type { Tools } from "../../src/tool" import type { RunOptions } from "../../src/tool-runtime" diff --git a/packages/llm/test/llm.test.ts b/packages/llm/test/llm.test.ts index a20c48411e..007b602ce3 100644 --- a/packages/llm/test/llm.test.ts +++ b/packages/llm/test/llm.test.ts @@ -1,18 +1,23 @@ import { describe, expect, test } from "bun:test" import { LLM, LLMResponse } from "../src" -import { LLMRequest, Message, ModelRef, ToolCallPart, ToolChoice, ToolDefinition, ToolResultPart } from "../src/schema" +import * as OpenAIChat from "../src/protocols/openai-chat" +import * as OpenAIResponses from "../src/protocols/openai-responses" +import { LLMRequest, Message, Model, ToolCallPart, ToolChoice, ToolDefinition, ToolResultPart } from "../src/schema" + +const chatRoute = OpenAIChat.route +const responsesRoute = OpenAIResponses.route describe("llm constructors", () => { test("builds canonical schema classes from ergonomic input", () => { const request = LLM.request({ id: "req_1", - model: LLM.model({ id: "fake-model", provider: "fake", route: "openai-chat", baseURL: "https://fake.local" }), + model: Model.make({ id: "fake-model", provider: "fake", route: chatRoute }), system: "You are concise.", prompt: "Say hello.", }) expect(request).toBeInstanceOf(LLMRequest) - expect(request.model).toBeInstanceOf(ModelRef) + expect(request.model).toBeInstanceOf(Model) expect(request.messages[0]).toBeInstanceOf(Message) expect(request.system).toEqual([{ type: "text", text: "You are concise." }]) expect(request.messages[0]?.content).toEqual([{ type: "text", text: "Say hello." }]) @@ -23,7 +28,7 @@ describe("llm constructors", () => { test("updates requests without spreading schema class instances", () => { const base = LLM.request({ id: "req_1", - model: LLM.model({ id: "fake-model", provider: "fake", route: "openai-chat", baseURL: "https://fake.local" }), + model: Model.make({ id: "fake-model", provider: "fake", route: chatRoute }), prompt: "Say hello.", }) const updated = LLM.updateRequest(base, { @@ -38,16 +43,16 @@ describe("llm constructors", () => { expect(updated.messages.map((message) => message.role)).toEqual(["user", "assistant"]) }) - test("keeps request options separate from model defaults", () => { + test("keeps request options separate from route defaults", () => { const request = LLM.request({ - model: LLM.model({ + model: Model.make({ id: "fake-model", provider: "fake", - route: "openai-chat", - baseURL: "https://fake.local", - generation: { maxTokens: 100, temperature: 1 }, - providerOptions: { openai: { store: false, metadata: { model: true } } }, - http: { body: { metadata: { model: true } }, headers: { "x-shared": "model" }, query: { model: "1" } }, + route: chatRoute.with({ + generation: { maxTokens: 100, temperature: 1 }, + providerOptions: { openai: { store: false, metadata: { model: true } } }, + http: { body: { metadata: { model: true } }, headers: { "x-shared": "model" }, query: { model: "1" } }, + }), }), prompt: "Say hello.", generation: { temperature: 0 }, @@ -67,7 +72,7 @@ describe("llm constructors", () => { test("updates canonical requests from the request datatype", () => { const base = LLM.request({ id: "req_1", - model: LLM.model({ id: "fake-model", provider: "fake", route: "openai-chat", baseURL: "https://fake.local" }), + model: Model.make({ id: "fake-model", provider: "fake", route: chatRoute }), prompt: "Say hello.", }) const updated = LLMRequest.update(base, { messages: [...base.messages, Message.assistant("Hi.")] }) @@ -80,14 +85,18 @@ describe("llm constructors", () => { }) test("updates canonical models from the model datatype", () => { - const base = LLM.model({ id: "fake-model", provider: "fake", route: "openai-chat", baseURL: "https://fake.local" }) - const updated = ModelRef.update(base, { route: "openai-responses" }) + const base = Model.make({ + id: "fake-model", + provider: "fake", + route: chatRoute, + }) + const updated = Model.update(base, { route: responsesRoute }) - expect(updated).toBeInstanceOf(ModelRef) + expect(updated).toBeInstanceOf(Model) expect(String(updated.id)).toBe("fake-model") - expect(updated.route).toBe("openai-responses") - expect(String(ModelRef.input(updated).provider)).toBe("fake") - expect(ModelRef.update(updated, {})).toBe(updated) + expect(updated.route).toBe(responsesRoute) + expect(String(Model.input(updated).provider)).toBe("fake") + expect(Model.update(updated, {})).toBe(updated) }) test("builds tool choices from names and tools", () => { @@ -105,7 +114,11 @@ describe("llm constructors", () => { expect(ToolChoice.make("required")).toEqual(new ToolChoice({ type: "required" })) expect( LLM.request({ - model: LLM.model({ id: "fake-model", provider: "fake", route: "openai-chat", baseURL: "https://fake.local" }), + model: Model.make({ + id: "fake-model", + provider: "fake", + route: chatRoute, + }), prompt: "Use tools if needed.", toolChoice: "required", }).toolChoice, diff --git a/packages/llm/test/provider.types.ts b/packages/llm/test/provider.types.ts index a04ce8bc60..f8b46e3753 100644 --- a/packages/llm/test/provider.types.ts +++ b/packages/llm/test/provider.types.ts @@ -1,9 +1,9 @@ import { Provider } from "../src/provider" -import { ProviderID, type ModelRef } from "../src/schema" +import { ProviderID, type Model } from "../src/schema" -declare const model: (id: string) => ModelRef -declare const requiredModel: (id: string, options: { readonly baseURL: string }) => ModelRef -declare const chat: (id: string, options: { readonly apiKey: string }) => ModelRef +declare const model: (id: string) => Model +declare const requiredModel: (id: string, options: { readonly baseURL: string }) => Model +declare const chat: (id: string, options: { readonly apiKey: string }) => Model Provider.make({ id: ProviderID.make("example"), @@ -22,6 +22,8 @@ const requiredProvider = Provider.make({ model: requiredModel, }) +// Provider.make is advanced structural typing coverage; built-in providers use +// configure(...).model(id) facades instead of second-argument selectors. requiredProvider.model("custom", { baseURL: "https://example.com/v1" }) // @ts-expect-error Provider.make preserves required model options. diff --git a/packages/llm/test/provider/anthropic-messages-cache.recorded.test.ts b/packages/llm/test/provider/anthropic-messages-cache.recorded.test.ts index 68b7e0a4ae..1044612b7a 100644 --- a/packages/llm/test/provider/anthropic-messages-cache.recorded.test.ts +++ b/packages/llm/test/provider/anthropic-messages-cache.recorded.test.ts @@ -3,14 +3,13 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { CacheHint, LLM } from "../../src" import { LLMClient } from "../../src/route" -import * as AnthropicMessages from "../../src/protocols/anthropic-messages" +import * as Anthropic from "../../src/providers/anthropic" import { LARGE_CACHEABLE_SYSTEM } from "../recorded-scenarios" import { recordedTests } from "../recorded-test" -const model = AnthropicMessages.model({ - id: "claude-haiku-4-5-20251001", +const model = Anthropic.configure({ apiKey: process.env.ANTHROPIC_API_KEY ?? "fixture", -}) +}).model("claude-haiku-4-5-20251001") // Two identical generations in a row. The first call writes the prefix into // Anthropic's cache; the second should report a cache read against the same diff --git a/packages/llm/test/provider/anthropic-messages.recorded.test.ts b/packages/llm/test/provider/anthropic-messages.recorded.test.ts index 5fefae51d4..7afcdcfda0 100644 --- a/packages/llm/test/provider/anthropic-messages.recorded.test.ts +++ b/packages/llm/test/provider/anthropic-messages.recorded.test.ts @@ -3,14 +3,13 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { LLM, LLMError, Message, ToolCallPart } from "../../src" import { LLMClient } from "../../src/route" -import * as AnthropicMessages from "../../src/protocols/anthropic-messages" +import * as Anthropic from "../../src/providers/anthropic" import { weatherToolName } from "../recorded-scenarios" import { recordedTests } from "../recorded-test" -const model = AnthropicMessages.model({ - id: "claude-haiku-4-5-20251001", +const model = Anthropic.configure({ apiKey: process.env.ANTHROPIC_API_KEY ?? "fixture", -}) +}).model("claude-haiku-4-5-20251001") const malformedToolOrderRequest = LLM.request({ id: "recorded_anthropic_malformed_tool_order", diff --git a/packages/llm/test/provider/anthropic-messages.test.ts b/packages/llm/test/provider/anthropic-messages.test.ts index 71204bcd63..5198af9ab7 100644 --- a/packages/llm/test/provider/anthropic-messages.test.ts +++ b/packages/llm/test/provider/anthropic-messages.test.ts @@ -1,17 +1,17 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" +import { HttpClientRequest } from "effect/unstable/http" import { CacheHint, LLM, LLMError, Message, ToolCallPart, Usage } from "../../src" -import { LLMClient } from "../../src/route" +import { Auth, LLMClient } from "../../src/route" import * as AnthropicMessages from "../../src/protocols/anthropic-messages" +import { continuationRequest, nativeAnthropicMessagesContinuation } from "../continuation-scenarios" import { it } from "../lib/effect" -import { fixedResponse } from "../lib/http" +import { dynamicResponse, fixedResponse } from "../lib/http" import { sseEvents } from "../lib/sse" -const model = AnthropicMessages.model({ - id: "claude-sonnet-4-5", - baseURL: "https://api.anthropic.test/v1/", - headers: { "x-api-key": "test" }, -}) +const model = AnthropicMessages.route + .with({ endpoint: { baseURL: "https://api.anthropic.test/v1/" }, auth: Auth.header("x-api-key", "test") }) + .model({ id: "claude-sonnet-4-5" }) const request = LLM.request({ id: "req_1", @@ -24,6 +24,19 @@ const request = LLM.request({ generation: { maxTokens: 20, temperature: 0 }, }) +type AnthropicToolResult = Extract< + AnthropicMessages.AnthropicMessagesBody["messages"][number]["content"][number], + { readonly type: "tool_result" } +> + +const expectToolResult = (body: AnthropicMessages.AnthropicMessagesBody): AnthropicToolResult => { + const result = body.messages + .flatMap((message) => (message.role === "user" ? message.content : [])) + .find((block): block is AnthropicToolResult => block.type === "tool_result") + expect(result).toBeDefined() + return result! +} + describe("Anthropic Messages route", () => { it.effect("prepares Anthropic Messages target", () => Effect.gen(function* () { @@ -42,7 +55,7 @@ describe("Anthropic Messages route", () => { it.effect("prepares tool call and tool result messages", () => Effect.gen(function* () { - const prepared = yield* LLMClient.prepare( + const prepared = yield* LLMClient.prepare( LLM.request({ id: "req_tool_result", model, @@ -71,6 +84,131 @@ describe("Anthropic Messages route", () => { }), ) + // Regression: screenshot/read tool results must stay structured so base64 + // image data is not JSON-stringified into `tool_result.content`. + it.effect("lowers image tool-result content as structured image blocks", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_image", + model, + messages: [ + Message.user("Show me the screenshot."), + Message.assistant([ToolCallPart.make({ id: "call_1", name: "read", input: { filePath: "shot.png" } })]), + Message.tool({ + id: "call_1", + name: "read", + resultType: "content", + result: [ + { type: "text", text: "Image read successfully" }, + { type: "media", mediaType: "image/png", data: "AAECAw==" }, + ], + }), + ], + cache: "none", + }), + ) + + expect(expectToolResult(prepared.body).content).toEqual([ + { type: "text", text: "Image read successfully" }, + { type: "image", source: { type: "base64", media_type: "image/png", data: "AAECAw==" } }, + ]) + }), + ) + + it.effect("lowers single-image tool-result content as a structured image block", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_image_only", + model, + messages: [ + Message.assistant([ToolCallPart.make({ id: "call_1", name: "screenshot", input: {} })]), + Message.tool({ + id: "call_1", + name: "screenshot", + resultType: "content", + result: [{ type: "media", mediaType: "image/jpeg", data: "/9j/AA==" }], + }), + ], + cache: "none", + }), + ) + + expect(expectToolResult(prepared.body).content).toEqual([ + { type: "image", source: { type: "base64", media_type: "image/jpeg", data: "/9j/AA==" } }, + ]) + }), + ) + + it.effect("rejects non-image media in tool-result content with a clear error", () => + Effect.gen(function* () { + const error = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_unsupported_media", + model, + messages: [ + Message.assistant([ToolCallPart.make({ id: "call_1", name: "fetch", input: {} })]), + Message.tool({ + id: "call_1", + name: "fetch", + resultType: "content", + result: [{ type: "media", mediaType: "audio/mpeg", data: "AAECAw==" }], + }), + ], + cache: "none", + }), + ).pipe(Effect.flip) + + expect(error.message).toContain("Anthropic Messages") + expect(error.message).toContain("audio/mpeg") + }), + ) + + it.effect("prepares the composed native continuation request", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + continuationRequest({ + id: "req_native_continuation_anthropic", + model, + features: nativeAnthropicMessagesContinuation, + }), + ) + + expect(prepared.body).toMatchObject({ + system: [{ type: "text", text: "You are concise. Continue from the provided history." }], + messages: [ + { + role: "user", + content: [ + { type: "text", text: "What is shown here?" }, + { type: "image", source: { type: "base64", media_type: "image/png", data: "AAECAw==" } }, + ], + }, + { + role: "assistant", + content: [ + { type: "thinking", thinking: "I inspected the previous turn.", signature: "sig_continuation_1" }, + { type: "text", text: "It shows a small test image." }, + ], + }, + { role: "user", content: [{ type: "text", text: "Check the weather in Paris before continuing." }] }, + { + role: "assistant", + content: [{ type: "tool_use", id: "call_weather_1", name: "get_weather", input: { city: "Paris" } }], + }, + { + role: "user", + content: [{ type: "tool_result", tool_use_id: "call_weather_1", content: '{"temperature":22}' }], + }, + { role: "assistant", content: [{ type: "text", text: "Paris is 22 degrees." }] }, + { role: "user", content: [{ type: "text", text: "Continue from this conversation in one short sentence." }] }, + ], + }) + expect(prepared.body.tools).toEqual([expect.objectContaining({ name: "get_weather" })]) + }), + ) + it.effect("lowers preserved Anthropic reasoning signature metadata", () => Effect.gen(function* () { const prepared = yield* LLMClient.prepare( @@ -199,7 +337,29 @@ describe("Anthropic Messages route", () => { ), ) - expect(response.events).toEqual([{ type: "provider-error", message: "Overloaded" }]) + // Prefix the error type so consumers can distinguish overloads, rate + // limits, and quota errors without parsing the message string. + expect(response.events).toEqual([{ type: "provider-error", message: "overloaded_error: Overloaded" }]) + }), + ) + + it.effect("falls back to error type when no message is present", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide(fixedResponse(sseEvents({ type: "error", error: { type: "overloaded_error", message: "" } }))), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "overloaded_error" }]) + }), + ) + + it.effect("falls back to a stable default when error payload is absent", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide(fixedResponse(sseEvents({ type: "error" }))), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "Anthropic Messages stream error" }]) }), ) @@ -394,17 +554,51 @@ describe("Anthropic Messages route", () => { }), ) - it.effect("rejects unsupported user media content", () => + it.effect("continues a conversation with user image content", () => Effect.gen(function* () { - const error = yield* LLMClient.prepare( + const response = yield* LLMClient.generate( LLM.request({ id: "req_media", model, - messages: [Message.user({ type: "media", mediaType: "image/png", data: "AAECAw==" })], + messages: [ + Message.user([ + { type: "text", text: "What is in this image?" }, + { type: "media", mediaType: "image/png", data: "AAECAw==" }, + ]), + ], }), - ).pipe(Effect.flip) + ).pipe( + Effect.provide( + dynamicResponse((input) => + Effect.gen(function* () { + const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie) + expect(yield* Effect.promise(() => web.json())).toMatchObject({ + messages: [ + { + role: "user", + content: [ + { type: "text", text: "What is in this image?" }, + { type: "image", source: { type: "base64", media_type: "image/png", data: "AAECAw==" } }, + ], + }, + ], + }) + return input.respond( + sseEvents( + { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } }, + { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "An image." } }, + { type: "content_block_stop", index: 0 }, + { type: "message_delta", delta: { stop_reason: "end_turn" }, usage: { output_tokens: 3 } }, + { type: "message_stop" }, + ), + { headers: { "content-type": "text/event-stream" } }, + ) + }), + ), + ), + ) - expect(error.message).toContain("Anthropic Messages user messages only support text content for now") + expect(response.text).toBe("An image.") }), ) diff --git a/packages/llm/test/provider/bedrock-converse-cache.recorded.test.ts b/packages/llm/test/provider/bedrock-converse-cache.recorded.test.ts index 2771046f80..8702e4eb40 100644 --- a/packages/llm/test/provider/bedrock-converse-cache.recorded.test.ts +++ b/packages/llm/test/provider/bedrock-converse-cache.recorded.test.ts @@ -2,7 +2,7 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { CacheHint, LLM } from "../../src" import { LLMClient } from "../../src/route" -import * as BedrockConverse from "../../src/protocols/bedrock-converse" +import { AmazonBedrock } from "../../src/providers" import { LARGE_CACHEABLE_SYSTEM } from "../recorded-scenarios" import { recordedTests } from "../recorded-test" @@ -12,15 +12,14 @@ const RECORDING_REGION = process.env.BEDROCK_RECORDING_REGION ?? "us-east-1" // doesn't reliably surface `cacheRead`/`cacheWrite` in usage, so the second // call wouldn't deterministically prove cache mapping works. Override with // BEDROCK_CACHE_MODEL_ID if your account has access elsewhere. -const model = BedrockConverse.model({ - id: process.env.BEDROCK_CACHE_MODEL_ID ?? "us.anthropic.claude-haiku-4-5-20251001-v1:0", +const model = AmazonBedrock.configure({ credentials: { region: RECORDING_REGION, accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? "fixture", secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? "fixture", sessionToken: process.env.AWS_SESSION_TOKEN, }, -}) +}).model(process.env.BEDROCK_CACHE_MODEL_ID ?? "us.anthropic.claude-haiku-4-5-20251001-v1:0") const cacheRequest = LLM.request({ id: "recorded_bedrock_cache", diff --git a/packages/llm/test/provider/bedrock-converse.test.ts b/packages/llm/test/provider/bedrock-converse.test.ts index ffdd6e8008..a3d8c5c626 100644 --- a/packages/llm/test/provider/bedrock-converse.test.ts +++ b/packages/llm/test/provider/bedrock-converse.test.ts @@ -4,7 +4,7 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { CacheHint, LLM, Message, ToolCallPart, ToolChoice } from "../../src" import { LLMClient } from "../../src/route" -import * as BedrockConverse from "../../src/protocols/bedrock-converse" +import { AmazonBedrock } from "../../src/providers" import { it } from "../lib/effect" import { fixedResponse } from "../lib/http" import { @@ -52,11 +52,10 @@ const eventStreamBody = (...payloads: ReadonlyArray) const fixedBytes = (bytes: Uint8Array) => fixedResponse(bytes.slice().buffer, { headers: { "content-type": "application/vnd.amazon.eventstream" } }) -const model = BedrockConverse.model({ - id: "anthropic.claude-3-5-sonnet-20240620-v1:0", +const model = AmazonBedrock.configure({ baseURL: "https://bedrock-runtime.test", apiKey: "test-bearer", -}) +}).model("anthropic.claude-3-5-sonnet-20240620-v1:0") const baseRequest = LLM.request({ id: "req_1", @@ -156,6 +155,55 @@ describe("Bedrock Converse route", () => { }), ) + it.effect("lowers image content in tool-result messages", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_image", + model, + messages: [ + Message.user("Capture the screen."), + Message.assistant([ToolCallPart.make({ id: "tool_1", name: "screenshot", input: {} })]), + Message.tool({ + id: "tool_1", + name: "screenshot", + result: { + type: "content", + value: [ + { type: "text", text: "Screenshot captured." }, + { type: "media", mediaType: "image/png", data: "AAAA" }, + ], + }, + }), + ], + cache: "none", + }), + ) + + expect(prepared.body).toMatchObject({ + messages: [ + { role: "user", content: [{ text: "Capture the screen." }] }, + { + role: "assistant", + content: [{ toolUse: { toolUseId: "tool_1", name: "screenshot", input: {} } }], + }, + { + role: "user", + content: [ + { + toolResult: { + toolUseId: "tool_1", + content: [{ text: "Screenshot captured." }, { image: { format: "png", source: { bytes: "AAAA" } } }], + status: "success", + }, + }, + ], + }, + ], + }) + }), + ) + it.effect("decodes text-delta + messageStop + metadata usage from binary event stream", () => Effect.gen(function* () { const body = eventStreamBody( @@ -249,39 +297,32 @@ describe("Bedrock Converse route", () => { it.effect("rejects requests with no auth path", () => Effect.gen(function* () { - const unsignedModel = BedrockConverse.model({ - id: "anthropic.claude-3-5-sonnet-20240620-v1:0", + const unsignedModel = AmazonBedrock.configure({ baseURL: "https://bedrock-runtime.test", - }) + }).model("anthropic.claude-3-5-sonnet-20240620-v1:0") const error = yield* LLMClient.generate(LLM.updateRequest(baseRequest, { model: unsignedModel })).pipe( Effect.provide(fixedBytes(eventStreamBody(["messageStop", { stopReason: "end_turn" }]))), Effect.flip, ) - expect(error.message).toContain("Bedrock Converse requires either model.apiKey") + expect(error.message).toContain("Bedrock Converse requires either route bearer auth or AWS credentials") }), ) it.effect("signs requests with SigV4 when AWS credentials are provided (deterministic plumbing check)", () => Effect.gen(function* () { - const signed = BedrockConverse.model({ - id: "anthropic.claude-3-5-sonnet-20240620-v1:0", + const signed = AmazonBedrock.configure({ baseURL: "https://bedrock-runtime.test", credentials: { region: "us-east-1", accessKeyId: "AKIAIOSFODNN7EXAMPLE", secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", }, - }) + }).model("anthropic.claude-3-5-sonnet-20240620-v1:0") const prepared = yield* LLMClient.prepare(LLM.updateRequest(baseRequest, { model: signed })) expect(prepared.route).toBe("bedrock-converse") - // The prepare phase doesn't sign — toHttp does. We assert the credential - // is plumbed onto the model native field for the signer to find. - expect(prepared.model.native).toMatchObject({ - aws_credentials: { region: "us-east-1", accessKeyId: "AKIAIOSFODNN7EXAMPLE" }, - aws_region: "us-east-1", - }) + expect(prepared.model).toBe(signed) }), ) @@ -531,18 +572,17 @@ describe("Bedrock Converse route", () => { const RECORDING_REGION = process.env.BEDROCK_RECORDING_REGION ?? "us-east-1" const recordedModel = () => - BedrockConverse.model({ + AmazonBedrock.configure({ // Most newer Anthropic models on Bedrock require a cross-region inference // profile (`us.` prefix). Nova does not require an Anthropic use-case form // and is on-demand-throughput accessible by default for most accounts. - id: process.env.BEDROCK_MODEL_ID ?? "us.amazon.nova-micro-v1:0", credentials: { region: RECORDING_REGION, accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? "fixture", secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? "fixture", sessionToken: process.env.AWS_SESSION_TOKEN, }, - }) + }).model(process.env.BEDROCK_MODEL_ID ?? "us.amazon.nova-micro-v1:0") const recorded = recordedTests({ prefix: "bedrock-converse", @@ -598,7 +638,6 @@ describe("Bedrock Converse recorded", () => { recorded.effect.with("drives a tool loop", { tags: ["tool", "tool-loop", "golden"] }, () => Effect.gen(function* () { - const llm = yield* LLMClient.Service expectWeatherToolLoop( yield* runWeatherToolLoop( weatherToolLoopRequest({ diff --git a/packages/llm/test/provider/cloudflare.test.ts b/packages/llm/test/provider/cloudflare.test.ts index 125e79bf9e..acd6396294 100644 --- a/packages/llm/test/provider/cloudflare.test.ts +++ b/packages/llm/test/provider/cloudflare.test.ts @@ -2,7 +2,7 @@ import { describe, expect } from "bun:test" import { ConfigProvider, Effect, Schema } from "effect" import { HttpClientRequest } from "effect/unstable/http" import { LLM } from "../../src" -import * as Cloudflare from "../../src/providers/cloudflare" +import { CloudflareAIGateway, CloudflareWorkersAI } from "../../src/providers/cloudflare" import { LLMClient } from "../../src/route" import { it } from "../lib/effect" import { dynamicResponse } from "../lib/http" @@ -21,18 +21,18 @@ const deltaChunk = (delta: object, finishReason: string | null = null) => ({ describe("Cloudflare", () => { it.effect("prepares AI Gateway models through the OpenAI-compatible Chat protocol", () => Effect.gen(function* () { - const model = Cloudflare.aiGateway("workers-ai/@cf/meta/llama-3.3-70b-instruct", { + const model = CloudflareAIGateway.configure({ accountId: "test-account", gatewayId: "test-gateway", apiKey: "test-token", - }) + }).model("workers-ai/@cf/meta/llama-3.3-70b-instruct") expect(model).toMatchObject({ id: "workers-ai/@cf/meta/llama-3.3-70b-instruct", provider: "cloudflare-ai-gateway", - route: "cloudflare-ai-gateway", - baseURL: "https://gateway.ai.cloudflare.com/v1/test-account/test-gateway/compat", + route: { id: "cloudflare-ai-gateway" }, }) + expect(model.route.endpoint.baseURL).toBe("https://gateway.ai.cloudflare.com/v1/test-account/test-gateway/compat") const prepared = yield* LLMClient.prepare(LLM.request({ model, prompt: "Say hello." })) @@ -49,11 +49,11 @@ describe("Cloudflare", () => { Effect.gen(function* () { const response = yield* LLM.generate( LLM.request({ - model: Cloudflare.aiGateway("openai/gpt-4o-mini", { + model: CloudflareAIGateway.configure({ accountId: "test-account", gatewayId: "test-gateway", apiKey: "test-token", - }), + }).model("openai/gpt-4o-mini"), prompt: "Say hello.", }), ).pipe( @@ -86,11 +86,11 @@ describe("Cloudflare", () => { it.effect("defaults AI Gateway id to default when omitted or blank", () => Effect.gen(function* () { expect( - Cloudflare.aiGateway("workers-ai/@cf/meta/llama-3.3-70b-instruct", { + CloudflareAIGateway.configure({ accountId: "test-account", gatewayId: "", gatewayApiKey: "test-token", - }).baseURL, + }).model("workers-ai/@cf/meta/llama-3.3-70b-instruct").route.endpoint.baseURL, ).toBe("https://gateway.ai.cloudflare.com/v1/test-account/default/compat") }), ) @@ -99,11 +99,11 @@ describe("Cloudflare", () => { Effect.gen(function* () { yield* LLM.generate( LLM.request({ - model: Cloudflare.aiGateway("openai/gpt-4o-mini", { + model: CloudflareAIGateway.configure({ accountId: "test-account", gatewayApiKey: "gateway-token", apiKey: "provider-token", - }), + }).model("openai/gpt-4o-mini"), prompt: "Say hello.", }), ).pipe( @@ -129,31 +129,31 @@ describe("Cloudflare", () => { Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: Cloudflare.aiGateway("openai/gpt-4o-mini", { + model: CloudflareAIGateway.configure({ baseURL: "https://gateway.proxy.test/v1/custom/compat", apiKey: "test-token", - }), + }).model("openai/gpt-4o-mini"), prompt: "Say hello.", }), ) - expect(prepared.model.baseURL).toBe("https://gateway.proxy.test/v1/custom/compat") + expect(prepared.model.route.endpoint.baseURL).toBe("https://gateway.proxy.test/v1/custom/compat") }), ) it.effect("prepares direct Workers AI models through the OpenAI-compatible Chat protocol", () => Effect.gen(function* () { - const model = Cloudflare.workersAI("@cf/meta/llama-3.1-8b-instruct", { + const model = CloudflareWorkersAI.configure({ accountId: "test-account", apiKey: "test-token", - }) + }).model("@cf/meta/llama-3.1-8b-instruct") expect(model).toMatchObject({ id: "@cf/meta/llama-3.1-8b-instruct", provider: "cloudflare-workers-ai", - route: "cloudflare-workers-ai", - baseURL: "https://api.cloudflare.com/client/v4/accounts/test-account/ai/v1", + route: { id: "cloudflare-workers-ai" }, }) + expect(model.route.endpoint.baseURL).toBe("https://api.cloudflare.com/client/v4/accounts/test-account/ai/v1") const prepared = yield* LLMClient.prepare(LLM.request({ model, prompt: "Say hello." })) @@ -170,10 +170,10 @@ describe("Cloudflare", () => { Effect.gen(function* () { const response = yield* LLM.generate( LLM.request({ - model: Cloudflare.workersAI("@cf/meta/llama-3.1-8b-instruct", { + model: CloudflareWorkersAI.configure({ accountId: "test-account", apiKey: "test-token", - }), + }).model("@cf/meta/llama-3.1-8b-instruct"), prompt: "Say hello.", }), ).pipe( @@ -205,9 +205,9 @@ describe("Cloudflare", () => { Effect.gen(function* () { yield* LLM.generate( LLM.request({ - model: Cloudflare.workersAI("@cf/meta/llama-3.1-8b-instruct", { + model: CloudflareWorkersAI.configure({ accountId: "test-account", - }), + }).model("@cf/meta/llama-3.1-8b-instruct"), prompt: "Say hello.", }), ).pipe( diff --git a/packages/llm/test/provider/gemini-cache.recorded.test.ts b/packages/llm/test/provider/gemini-cache.recorded.test.ts index b86980c43d..d210c5c024 100644 --- a/packages/llm/test/provider/gemini-cache.recorded.test.ts +++ b/packages/llm/test/provider/gemini-cache.recorded.test.ts @@ -2,14 +2,13 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { LLM } from "../../src" import { LLMClient } from "../../src/route" -import * as Gemini from "../../src/protocols/gemini" +import * as Google from "../../src/providers/google" import { LARGE_CACHEABLE_SYSTEM } from "../recorded-scenarios" import { recordedTests } from "../recorded-test" -const model = Gemini.model({ - id: "gemini-2.5-flash", +const model = Google.configure({ apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? process.env.GEMINI_API_KEY ?? "fixture", -}) +}).model("gemini-2.5-flash") // Gemini does implicit prefix caching on 2.5+ models above ~1024 tokens. The // `CacheHint` is currently a no-op for Gemini (the explicit `CachedContent` diff --git a/packages/llm/test/provider/gemini.test.ts b/packages/llm/test/provider/gemini.test.ts index 7e6bbc8466..9e519723f1 100644 --- a/packages/llm/test/provider/gemini.test.ts +++ b/packages/llm/test/provider/gemini.test.ts @@ -1,17 +1,18 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { LLM, LLMError, Message, ToolCallPart, Usage } from "../../src" -import { LLMClient } from "../../src/route" +import { Auth, LLMClient } from "../../src/route" import * as Gemini from "../../src/protocols/gemini" import { it } from "../lib/effect" import { fixedResponse } from "../lib/http" import { sseEvents, sseRaw } from "../lib/sse" -const model = Gemini.model({ - id: "gemini-2.5-flash", - baseURL: "https://generativelanguage.test/v1beta/", - headers: { "x-goog-api-key": "test" }, -}) +const model = Gemini.route + .with({ + endpoint: { baseURL: "https://generativelanguage.test/v1beta/" }, + auth: Auth.header("x-goog-api-key", "test"), + }) + .model({ id: "gemini-2.5-flash" }) const request = LLM.request({ id: "req_1", diff --git a/packages/llm/test/provider/golden.recorded.test.ts b/packages/llm/test/provider/golden.recorded.test.ts index 3fa27c706e..79d8589cf8 100644 --- a/packages/llm/test/provider/golden.recorded.test.ts +++ b/packages/llm/test/provider/golden.recorded.test.ts @@ -1,32 +1,30 @@ import { Redactor } from "@opencode-ai/http-recorder" -import * as AnthropicMessages from "../../src/protocols/anthropic-messages" -import * as Gemini from "../../src/protocols/gemini" -import * as OpenAIChat from "../../src/protocols/openai-chat" -import * as OpenAIResponses from "../../src/protocols/openai-responses" -import * as Cloudflare from "../../src/providers/cloudflare" +import * as Anthropic from "../../src/providers/anthropic" +import { CloudflareAIGateway, CloudflareWorkersAI } from "../../src/providers/cloudflare" +import * as Google from "../../src/providers/google" import * as OpenAI from "../../src/providers/openai" import * as OpenAICompatible from "../../src/providers/openai-compatible" import * as OpenRouter from "../../src/providers/openrouter" import * as XAI from "../../src/providers/xai" import { describeRecordedGoldenScenarios } from "../recorded-golden" -const openAIChat = OpenAIChat.model({ id: "gpt-4o-mini", apiKey: process.env.OPENAI_API_KEY ?? "fixture" }) -const openAIResponses = OpenAIResponses.model({ id: "gpt-5.5", apiKey: process.env.OPENAI_API_KEY ?? "fixture" }) -const openAIResponsesWebSocket = OpenAI.responsesWebSocket("gpt-4.1-mini", { +const openAI = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY ?? "fixture", }) -const anthropicHaiku = AnthropicMessages.model({ - id: "claude-haiku-4-5-20251001", +const openAIChat = openAI.chat("gpt-4o-mini") +const openAIResponses = openAI.responses("gpt-5.5") +const openAIResponsesWebSocket = openAI.responsesWebSocket("gpt-4.1-mini") +const anthropic = Anthropic.configure({ apiKey: process.env.ANTHROPIC_API_KEY ?? "fixture", }) -const anthropicOpus = AnthropicMessages.model({ - id: "claude-opus-4-7", - apiKey: process.env.ANTHROPIC_API_KEY ?? "fixture", -}) -const gemini = Gemini.model({ id: "gemini-2.5-flash", apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? "fixture" }) -const xaiBasic = XAI.model("grok-3-mini", { apiKey: process.env.XAI_API_KEY ?? "fixture" }) -const xaiFlagship = XAI.model("grok-4.3", { apiKey: process.env.XAI_API_KEY ?? "fixture" }) -const cloudflareAIGatewayWorkers = Cloudflare.aiGateway("workers-ai/@cf/meta/llama-3.1-8b-instruct", { +const anthropicHaiku = anthropic.model("claude-haiku-4-5-20251001") +const anthropicOpus = anthropic.model("claude-opus-4-7") +const google = Google.configure({ apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? "fixture" }) +const gemini = google.model("gemini-2.5-flash") +const xai = XAI.configure({ apiKey: process.env.XAI_API_KEY ?? "fixture" }) +const xaiBasic = xai.model("grok-3-mini") +const xaiFlagship = xai.model("grok-4.3") +const cloudflareAIGateway = CloudflareAIGateway.configure({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID ?? "fixture-account", gatewayId: process.env.CLOUDFLARE_GATEWAY_ID && process.env.CLOUDFLARE_GATEWAY_ID !== process.env.CLOUDFLARE_ACCOUNT_ID @@ -34,32 +32,31 @@ const cloudflareAIGatewayWorkers = Cloudflare.aiGateway("workers-ai/@cf/meta/lla : undefined, gatewayApiKey: process.env.CLOUDFLARE_API_TOKEN ?? "fixture", }) -const cloudflareAIGatewayWorkersTools = Cloudflare.aiGateway("workers-ai/@cf/openai/gpt-oss-20b", { - accountId: process.env.CLOUDFLARE_ACCOUNT_ID ?? "fixture-account", - gatewayId: - process.env.CLOUDFLARE_GATEWAY_ID && process.env.CLOUDFLARE_GATEWAY_ID !== process.env.CLOUDFLARE_ACCOUNT_ID - ? process.env.CLOUDFLARE_GATEWAY_ID - : undefined, - gatewayApiKey: process.env.CLOUDFLARE_API_TOKEN ?? "fixture", -}) -const cloudflareWorkersAI = Cloudflare.workersAI("@cf/meta/llama-3.1-8b-instruct", { +const cloudflareWorkers = CloudflareWorkersAI.configure({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID ?? "fixture-account", apiKey: process.env.CLOUDFLARE_API_KEY ?? "fixture", }) -const cloudflareWorkersAITools = Cloudflare.workersAI("@cf/openai/gpt-oss-20b", { - accountId: process.env.CLOUDFLARE_ACCOUNT_ID ?? "fixture-account", - apiKey: process.env.CLOUDFLARE_API_KEY ?? "fixture", -}) -const deepseek = OpenAICompatible.deepseek.model("deepseek-chat", { apiKey: process.env.DEEPSEEK_API_KEY ?? "fixture" }) -const together = OpenAICompatible.togetherai.model("meta-llama/Llama-3.3-70B-Instruct-Turbo", { - apiKey: process.env.TOGETHER_AI_API_KEY ?? "fixture", -}) -const groq = OpenAICompatible.groq.model("llama-3.3-70b-versatile", { apiKey: process.env.GROQ_API_KEY ?? "fixture" }) -const openrouter = OpenRouter.model("openai/gpt-4o-mini", { apiKey: process.env.OPENROUTER_API_KEY ?? "fixture" }) -const openrouterGpt55 = OpenRouter.model("openai/gpt-5.5", { apiKey: process.env.OPENROUTER_API_KEY ?? "fixture" }) -const openrouterOpus = OpenRouter.model("anthropic/claude-opus-4.7", { +const cloudflareAIGatewayWorkers = cloudflareAIGateway.model("workers-ai/@cf/meta/llama-3.1-8b-instruct") +const cloudflareAIGatewayWorkersTools = cloudflareAIGateway.model("workers-ai/@cf/openai/gpt-oss-20b") +const cloudflareWorkersAI = cloudflareWorkers.model("@cf/meta/llama-3.1-8b-instruct") +const cloudflareWorkersAITools = cloudflareWorkers.model("@cf/openai/gpt-oss-20b") +const deepseek = OpenAICompatible.deepseek + .configure({ apiKey: process.env.DEEPSEEK_API_KEY ?? "fixture" }) + .model("deepseek-chat") +const together = OpenAICompatible.togetherai + .configure({ + apiKey: process.env.TOGETHER_AI_API_KEY ?? "fixture", + }) + .model("meta-llama/Llama-3.3-70B-Instruct-Turbo") +const groq = OpenAICompatible.groq + .configure({ apiKey: process.env.GROQ_API_KEY ?? "fixture" }) + .model("llama-3.3-70b-versatile") +const openRouter = OpenRouter.configure({ apiKey: process.env.OPENROUTER_API_KEY ?? "fixture" }) +const openrouter = openRouter.model("openai/gpt-4o-mini") +const openrouterGpt55 = openRouter.model("openai/gpt-5.5") +const openrouterOpus = OpenRouter.configure({ apiKey: process.env.OPENROUTER_API_KEY ?? "fixture", -}) +}).model("anthropic/claude-opus-4.7") const redactCloudflareURL = (url: string) => url @@ -86,8 +83,11 @@ describeRecordedGoldenScenarios([ tags: ["flagship"], scenarios: [ { id: "text", temperature: false }, + { id: "reasoning", temperature: false }, + { id: "reasoning-continuation", temperature: false }, { id: "tool-call", temperature: false }, { id: "tool-loop", temperature: false }, + { id: "image-tool-result", temperature: false, maxTokens: 40 }, ], }, { @@ -113,14 +113,17 @@ describeRecordedGoldenScenarios([ requires: ["ANTHROPIC_API_KEY"], tags: ["flagship"], options: { redactor: Redactor.defaults({ requestHeaders: { allow: ["content-type", "anthropic-version"] } }) }, - scenarios: [{ id: "tool-loop", temperature: false }], + scenarios: [ + { id: "tool-loop", temperature: false }, + { id: "image-tool-result", temperature: false, maxTokens: 40 }, + ], }, { name: "Gemini 2.5 Flash", prefix: "gemini", model: gemini, requires: ["GOOGLE_GENERATIVE_AI_API_KEY"], - scenarios: [{ id: "text", maxTokens: 80 }, "tool-call"], + scenarios: [{ id: "text", maxTokens: 80 }, "tool-call", { id: "image", maxTokens: 160 }], }, { name: "xAI Grok 3 Mini", diff --git a/packages/llm/test/provider/openai-chat.test.ts b/packages/llm/test/provider/openai-chat.test.ts index 4303a69ffa..5d1b412bfa 100644 --- a/packages/llm/test/provider/openai-chat.test.ts +++ b/packages/llm/test/provider/openai-chat.test.ts @@ -1,11 +1,11 @@ import { describe, expect } from "bun:test" import { Effect, Schema, Stream } from "effect" import { HttpClientRequest } from "effect/unstable/http" -import { LLM, LLMError, Message, ToolCallPart, Usage } from "../../src" +import { LLM, LLMError, Message, Model, ToolCallPart, Usage } from "../../src" import * as Azure from "../../src/providers/azure" import * as OpenAI from "../../src/providers/openai" import * as OpenAIChat from "../../src/protocols/openai-chat" -import { LLMClient } from "../../src/route" +import { Auth, LLMClient } from "../../src/route" import { it } from "../lib/effect" import { dynamicResponse, fixedResponse, truncatedStream } from "../lib/http" import { deltaChunk, usageChunk } from "../lib/openai-chunks" @@ -15,11 +15,9 @@ const TargetJson = Schema.fromJsonString(Schema.Unknown) const encodeJson = Schema.encodeSync(TargetJson) const decodeJson = Schema.decodeUnknownSync(TargetJson) -const model = OpenAIChat.model({ - id: "gpt-4o-mini", - baseURL: "https://api.openai.test/v1/", - headers: { authorization: "Bearer test" }, -}) +const model = OpenAIChat.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") }) + .model({ id: "gpt-4o-mini" }) const request = LLM.request({ id: "req_1", @@ -56,7 +54,7 @@ describe("OpenAI Chat route", () => { Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: OpenAI.chat("gpt-4o-mini", { baseURL: "https://api.openai.test/v1/" }), + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).chat("gpt-4o-mini"), prompt: "think", providerOptions: { openai: { reasoningEffort: "low" } }, }), @@ -69,7 +67,9 @@ describe("OpenAI Chat route", () => { it.effect("adds native query params to the Chat Completions URL", () => LLMClient.generate( - LLM.updateRequest(request, { model: OpenAIChat.model({ ...model, queryParams: { "api-version": "v1" } }) }), + LLM.updateRequest(request, { + model: Model.update(model, { route: model.route.with({ endpoint: { query: { "api-version": "v1" } } }) }), + }), ).pipe( Effect.provide( dynamicResponse((input) => @@ -88,17 +88,18 @@ describe("OpenAI Chat route", () => { it.effect("uses Azure api-key header for static OpenAI Chat keys", () => LLMClient.generate( LLM.updateRequest(request, { - model: Azure.chat("gpt-4o-mini", { + model: Azure.configure({ baseURL: "https://opencode-test.openai.azure.com/openai/v1/", apiKey: "azure-key", headers: { authorization: "Bearer stale" }, - }), + }).chat("gpt-4o-mini"), }), ).pipe( Effect.provide( dynamicResponse((input) => Effect.gen(function* () { const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie) + expect(web.url).toBe("https://opencode-test.openai.azure.com/openai/v1/chat/completions?api-version=v1") expect(web.headers.get("api-key")).toBe("azure-key") expect(web.headers.get("authorization")).toBeNull() return input.respond(sseEvents(deltaChunk({}, "stop")), { @@ -113,7 +114,9 @@ describe("OpenAI Chat route", () => { it.effect("applies serializable HTTP overlays after payload lowering", () => LLMClient.generate( LLM.updateRequest(request, { - model: OpenAIChat.model({ ...model, apiKey: "fresh-key", headers: { authorization: "Bearer stale" } }), + model: model.route + .with({ auth: Auth.bearer("fresh-key"), headers: { authorization: "Bearer stale" } }) + .model({ id: model.id }), http: { body: { metadata: { source: "test" } }, headers: { authorization: "Bearer request", "x-custom": "yes" }, @@ -257,6 +260,32 @@ describe("OpenAI Chat route", () => { }), ) + it.effect("parses OpenAI-compatible reasoning content deltas", () => + Effect.gen(function* () { + const body = sseEvents( + { choices: [{ delta: { reasoning_content: "thinking" } }] }, + { choices: [{ delta: { content: "Hello" } }] }, + { choices: [{ delta: {}, finish_reason: "stop" }] }, + ) + + const response = yield* LLMClient.generate(request).pipe(Effect.provide(fixedResponse(body))) + + expect(response.reasoning).toBe("thinking") + expect(response.text).toBe("Hello") + expect(response.events).toMatchObject([ + { type: "step-start", index: 0 }, + { type: "reasoning-start", id: "reasoning-0" }, + { type: "reasoning-delta", id: "reasoning-0", text: "thinking" }, + { type: "text-start", id: "text-0" }, + { type: "text-delta", id: "text-0", text: "Hello" }, + { type: "reasoning-end", id: "reasoning-0" }, + { type: "text-end", id: "text-0" }, + { type: "step-finish", index: 0, reason: "stop" }, + { type: "finish", reason: "stop" }, + ]) + }), + ) + it.effect("assembles streamed tool call input", () => Effect.gen(function* () { const body = sseEvents( diff --git a/packages/llm/test/provider/openai-compatible-chat.test.ts b/packages/llm/test/provider/openai-compatible-chat.test.ts index 50aac41091..43ae283e9f 100644 --- a/packages/llm/test/provider/openai-compatible-chat.test.ts +++ b/packages/llm/test/provider/openai-compatible-chat.test.ts @@ -2,7 +2,7 @@ import { describe, expect } from "bun:test" import { Effect, Schema } from "effect" import { HttpClientRequest } from "effect/unstable/http" import { LLM, Message, ToolCallPart } from "../../src" -import { LLMClient } from "../../src/route" +import { Auth, LLMClient } from "../../src/route" import * as OpenAICompatible from "../../src/providers/openai-compatible" import * as OpenAICompatibleChat from "../../src/protocols/openai-compatible-chat" import { it } from "../lib/effect" @@ -12,13 +12,13 @@ import { sseEvents } from "../lib/sse" const Json = Schema.fromJsonString(Schema.Unknown) const decodeJson = Schema.decodeUnknownSync(Json) -const model = OpenAICompatibleChat.model({ - id: "deepseek-chat", - provider: "deepseek", - baseURL: "https://api.deepseek.test/v1/", - apiKey: "test-key", - queryParams: { "api-version": "2026-01-01" }, -}) +const model = OpenAICompatibleChat.route + .with({ + provider: "deepseek", + endpoint: { baseURL: "https://api.deepseek.test/v1/", query: { "api-version": "2026-01-01" } }, + auth: Auth.bearer("test-key"), + }) + .model({ id: "deepseek-chat" }) const request = LLM.request({ id: "req_1", @@ -63,10 +63,11 @@ describe("OpenAI-compatible Chat route", () => { expect(prepared.model).toMatchObject({ id: "deepseek-chat", provider: "deepseek", - route: "openai-compatible-chat", + route: { id: "openai-compatible-chat" }, + }) + expect(prepared.model.route.endpoint).toMatchObject({ baseURL: "https://api.deepseek.test/v1/", - apiKey: "test-key", - queryParams: { "api-version": "2026-01-01" }, + query: { "api-version": "2026-01-01" }, }) expect(prepared.body).toEqual({ model: "deepseek-chat", @@ -93,13 +94,12 @@ describe("OpenAI-compatible Chat route", () => { Effect.gen(function* () { expect( providerFamilies.map(([provider, family]) => { - const model = family.model(`${provider}-model`, { apiKey: "test-key" }) + const model = family.configure({ apiKey: "test-key" }).model(`${provider}-model`) return { id: String(model.id), provider: String(model.provider), - route: model.route, - baseURL: model.baseURL, - apiKey: model.apiKey, + route: model.route.id, + baseURL: model.route.endpoint.baseURL, } }), ).toEqual( @@ -108,19 +108,20 @@ describe("OpenAI-compatible Chat route", () => { provider, route: "openai-compatible-chat", baseURL, - apiKey: "test-key", })), ) - const custom = OpenAICompatible.deepseek.model("deepseek-chat", { - apiKey: "test-key", - baseURL: "https://custom.deepseek.test/v1", - }) + const custom = OpenAICompatible.deepseek + .configure({ + apiKey: "test-key", + baseURL: "https://custom.deepseek.test/v1", + }) + .model("deepseek-chat") expect(custom).toMatchObject({ provider: "deepseek", - route: "openai-compatible-chat", - baseURL: "https://custom.deepseek.test/v1", + route: { id: "openai-compatible-chat" }, }) + expect(custom.route.endpoint.baseURL).toBe("https://custom.deepseek.test/v1") }), ) diff --git a/packages/llm/test/provider/openai-responses-cache.recorded.test.ts b/packages/llm/test/provider/openai-responses-cache.recorded.test.ts index 2b67a0a4f2..638c30e667 100644 --- a/packages/llm/test/provider/openai-responses-cache.recorded.test.ts +++ b/packages/llm/test/provider/openai-responses-cache.recorded.test.ts @@ -2,14 +2,13 @@ import { describe, expect } from "bun:test" import { Effect } from "effect" import { LLM } from "../../src" import { LLMClient } from "../../src/route" -import * as OpenAIResponses from "../../src/protocols/openai-responses" +import * as OpenAI from "../../src/providers/openai" import { LARGE_CACHEABLE_SYSTEM } from "../recorded-scenarios" import { recordedTests } from "../recorded-test" -const model = OpenAIResponses.model({ - id: "gpt-4.1-mini", +const model = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY ?? "fixture", -}) +}).responses("gpt-4.1-mini") // OpenAI caches prefixes automatically once they cross the 1024-token threshold; // `CacheHint` is a no-op for the wire body. The stable signal is the diff --git a/packages/llm/test/provider/openai-responses.test.ts b/packages/llm/test/provider/openai-responses.test.ts index 63452f61b0..3f291728ab 100644 --- a/packages/llm/test/provider/openai-responses.test.ts +++ b/packages/llm/test/provider/openai-responses.test.ts @@ -1,21 +1,20 @@ import { describe, expect } from "bun:test" import { ConfigProvider, Effect, Layer, Stream } from "effect" import { Headers, HttpClientRequest } from "effect/unstable/http" -import { LLM, LLMError, Message, ToolCallPart, Usage } from "../../src" +import { LLM, LLMError, Message, Model, ToolCallPart, Usage } from "../../src" import { Auth, LLMClient, RequestExecutor, WebSocketExecutor } from "../../src/route" import * as Azure from "../../src/providers/azure" import * as OpenAI from "../../src/providers/openai" import * as OpenAIResponses from "../../src/protocols/openai-responses" import * as ProviderShared from "../../src/protocols/shared" +import { continuationRequest, nativeOpenAIResponsesContinuation } from "../continuation-scenarios" import { it } from "../lib/effect" import { dynamicResponse, fixedResponse } from "../lib/http" import { sseEvents } from "../lib/sse" -const model = OpenAIResponses.model({ - id: "gpt-4.1-mini", - baseURL: "https://api.openai.test/v1/", - headers: { authorization: "Bearer test" }, -}) +const model = OpenAIResponses.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") }) + .model({ id: "gpt-4.1-mini" }) const request = LLM.request({ id: "req_1", @@ -27,6 +26,19 @@ const request = LLM.request({ const configEnv = (env: Record) => Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env }))) +type OpenAIToolOutput = Extract< + OpenAIResponses.OpenAIResponsesBody["input"][number], + { readonly type: "function_call_output" } +> + +const expectToolOutput = (body: OpenAIResponses.OpenAIResponsesBody): OpenAIToolOutput => { + const output = body.input.find( + (item): item is OpenAIToolOutput => "type" in item && item.type === "function_call_output", + ) + expect(output).toBeDefined() + return output! +} + describe("OpenAI Responses route", () => { it.effect("prepares OpenAI Responses target", () => Effect.gen(function* () { @@ -49,7 +61,9 @@ describe("OpenAI Responses route", () => { Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.updateRequest(request, { - model: OpenAI.responsesWebSocket("gpt-4.1-mini", { baseURL: "https://api.openai.test/v1/", apiKey: "test" }), + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).responsesWebSocket( + "gpt-4.1-mini", + ), }), ) @@ -95,10 +109,12 @@ describe("OpenAI Responses route", () => { ) const response = yield* LLMClient.generate( LLM.request({ - model: OpenAI.responsesWebSocket("gpt-4.1-mini", { baseURL: "https://api.openai.test/v1/", apiKey: "test" }), + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).responsesWebSocket( + "gpt-4.1-mini", + ), prompt: "Say hello.", }), - ).pipe(Effect.provide(LLMClient.layerWithWebSocket.pipe(Layer.provide(deps)))) + ).pipe(Effect.provide(LLMClient.layer.pipe(Layer.provide(deps)))) expect(response.text).toBe("Hi") expect(opened).toEqual([{ url: "wss://api.openai.test/v1/responses", authorization: "Bearer test" }]) @@ -113,36 +129,10 @@ describe("OpenAI Responses route", () => { }), ) - it.effect("requires WebSocket runtime for OpenAI Responses WebSocket", () => - Effect.gen(function* () { - const error = yield* LLMClient.generate( - LLM.request({ - model: OpenAI.responsesWebSocket("gpt-4.1-mini", { baseURL: "https://api.openai.test/v1/", apiKey: "test" }), - prompt: "Say hello.", - }), - ).pipe( - Effect.provide( - LLMClient.layer.pipe( - Layer.provide( - Layer.succeed( - RequestExecutor.Service, - RequestExecutor.Service.of({ - execute: () => Effect.die("unexpected HTTP request"), - }), - ), - ), - ), - ), - Effect.flip, - ) - - expect(error.message).toContain("requires WebSocketExecutor.Service") - }), - ) - it.effect("fails immediately when WebSocket is already closed", () => Effect.gen(function* () { const error = yield* WebSocketExecutor.fromWebSocket( + // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- fromWebSocket reads readyState before touching WebSocket methods on this branch. { readyState: globalThis.WebSocket.CLOSED } as globalThis.WebSocket, { url: "wss://api.openai.test/v1/responses", headers: Headers.empty }, ).pipe(Effect.flip) @@ -155,7 +145,7 @@ describe("OpenAI Responses route", () => { Effect.gen(function* () { yield* LLMClient.generate( LLM.updateRequest(request, { - model: OpenAIResponses.model({ ...model, queryParams: { "api-version": "v1" } }), + model: Model.update(model, { route: model.route.with({ endpoint: { query: { "api-version": "v1" } } }) }), }), ).pipe( Effect.provide( @@ -177,17 +167,18 @@ describe("OpenAI Responses route", () => { Effect.gen(function* () { yield* LLMClient.generate( LLM.updateRequest(request, { - model: Azure.responses("gpt-4.1-mini", { + model: Azure.configure({ baseURL: "https://opencode-test.openai.azure.com/openai/v1/", apiKey: "azure-key", headers: { authorization: "Bearer stale" }, - }), + }).responses("gpt-4.1-mini"), }), ).pipe( Effect.provide( dynamicResponse((input) => Effect.gen(function* () { const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie) + expect(web.url).toBe("https://opencode-test.openai.azure.com/openai/v1/responses?api-version=v1") expect(web.headers.get("api-key")).toBe("azure-key") expect(web.headers.get("authorization")).toBeNull() return input.respond(sseEvents({ type: "response.completed", response: {} }), { @@ -203,7 +194,7 @@ describe("OpenAI Responses route", () => { it.effect("loads OpenAI default auth from Effect Config", () => LLMClient.generate( LLM.updateRequest(request, { - model: OpenAI.responses("gpt-4.1-mini", { baseURL: "https://api.openai.test/v1/" }), + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/" }).responses("gpt-4.1-mini"), }), ).pipe( configEnv({ OPENAI_API_KEY: "env-key" }), @@ -224,10 +215,10 @@ describe("OpenAI Responses route", () => { it.effect("lets explicit auth override OpenAI default API key auth", () => LLMClient.generate( LLM.updateRequest(request, { - model: OpenAI.responses("gpt-4.1-mini", { + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", auth: Auth.bearer("oauth-token"), - }), + }).responses("gpt-4.1-mini"), }), ).pipe( Effect.provide( @@ -270,11 +261,132 @@ describe("OpenAI Responses route", () => { }), ) + // Regression: screenshot/read tool results must stay structured so base64 + // image data is not JSON-stringified into `function_call_output.output`. + it.effect("lowers image tool-result content as structured input_image items", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_image", + model, + messages: [ + Message.user("Show me the screenshot."), + Message.assistant([ToolCallPart.make({ id: "call_1", name: "read", input: { filePath: "shot.png" } })]), + Message.tool({ + id: "call_1", + name: "read", + resultType: "content", + result: [ + { type: "text", text: "Image read successfully" }, + { type: "media", mediaType: "image/png", data: "AAECAw==" }, + ], + }), + ], + }), + ) + + expect(expectToolOutput(prepared.body).output).toEqual([ + { type: "input_text", text: "Image read successfully" }, + { type: "input_image", image_url: "data:image/png;base64,AAECAw==" }, + ]) + }), + ) + + it.effect("lowers single-image tool-result content as structured input_image array", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_image_only", + model, + messages: [ + Message.assistant([ToolCallPart.make({ id: "call_1", name: "screenshot", input: {} })]), + Message.tool({ + id: "call_1", + name: "screenshot", + resultType: "content", + result: [{ type: "media", mediaType: "image/png", data: "AAECAw==" }], + }), + ], + }), + ) + + expect(expectToolOutput(prepared.body).output).toEqual([ + { type: "input_image", image_url: "data:image/png;base64,AAECAw==" }, + ]) + }), + ) + + it.effect("rejects non-image media in tool-result content with a clear error", () => + Effect.gen(function* () { + const error = yield* LLMClient.prepare( + LLM.request({ + id: "req_tool_result_unsupported_media", + model, + messages: [ + Message.assistant([ToolCallPart.make({ id: "call_1", name: "fetch", input: {} })]), + Message.tool({ + id: "call_1", + name: "fetch", + resultType: "content", + result: [{ type: "media", mediaType: "audio/mpeg", data: "AAECAw==" }], + }), + ], + }), + ).pipe(Effect.flip) + + expect(error.message).toContain("OpenAI Responses") + expect(error.message).toContain("audio/mpeg") + }), + ) + + it.effect("prepares the composed native continuation request", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + continuationRequest({ + id: "req_native_continuation_openai", + model, + features: nativeOpenAIResponsesContinuation, + }), + ) + + expect(prepared.body).toMatchObject({ + input: [ + { role: "system", content: "You are concise. Continue from the provided history." }, + { + role: "user", + content: [ + { type: "input_text", text: "What is shown here?" }, + { type: "input_image", image_url: "data:image/png;base64,AAECAw==" }, + ], + }, + { + type: "reasoning", + id: "rs_continuation_1", + encrypted_content: "encrypted-continuation-state", + summary: [{ type: "summary_text", text: "I inspected the previous turn." }], + }, + { role: "assistant", content: [{ type: "output_text", text: "It shows a small test image." }] }, + { role: "user", content: [{ type: "input_text", text: "Check the weather in Paris before continuing." }] }, + { type: "function_call", call_id: "call_weather_1", name: "get_weather", arguments: '{"city":"Paris"}' }, + { type: "function_call_output", call_id: "call_weather_1", output: '{"temperature":22}' }, + { role: "assistant", content: [{ type: "output_text", text: "Paris is 22 degrees." }] }, + { + role: "user", + content: [{ type: "input_text", text: "Continue from this conversation in one short sentence." }], + }, + ], + include: ["reasoning.encrypted_content"], + store: false, + }) + expect(prepared.body.tools).toEqual([expect.objectContaining({ type: "function", name: "get_weather" })]) + }), + ) + it.effect("maps OpenAI provider options to Responses options", () => Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: OpenAI.model("gpt-5.2", { baseURL: "https://api.openai.test/v1/" }), + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", apiKey: "test" }).model("gpt-5.2"), prompt: "think", providerOptions: { openai: { @@ -295,14 +407,15 @@ describe("OpenAI Responses route", () => { }), ) - it.effect("request OpenAI provider options override model defaults", () => + it.effect("request OpenAI provider options override route defaults", () => Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: OpenAI.model("gpt-4.1-mini", { + model: OpenAI.configure({ baseURL: "https://api.openai.test/v1/", + apiKey: "test", providerOptions: { openai: { promptCacheKey: "model_cache" } }, - }), + }).model("gpt-4.1-mini"), prompt: "no cache", providerOptions: { openai: { promptCacheKey: "request_cache" } }, }), @@ -375,6 +488,199 @@ describe("OpenAI Responses route", () => { }), ) + it.effect("parses reasoning summary stream fixtures", () => + Effect.gen(function* () { + const body = sseEvents( + { type: "response.reasoning_summary_text.delta", item_id: "rs_1", delta: "thinking" }, + { type: "response.output_text.delta", item_id: "msg_1", delta: "Hello" }, + { type: "response.reasoning_summary_text.done", item_id: "rs_1" }, + { type: "response.completed", response: { id: "resp_1" } }, + ) + + const response = yield* LLMClient.generate(request).pipe(Effect.provide(fixedResponse(body))) + + expect(response.reasoning).toBe("thinking") + expect(response.text).toBe("Hello") + expect(response.events).toMatchObject([ + { type: "step-start", index: 0 }, + { type: "reasoning-start", id: "rs_1" }, + { type: "reasoning-delta", id: "rs_1", text: "thinking" }, + { type: "text-start", id: "msg_1" }, + { type: "text-delta", id: "msg_1", text: "Hello" }, + { type: "reasoning-end", id: "rs_1" }, + { type: "text-end", id: "msg_1" }, + { type: "step-finish", index: 0, reason: "stop" }, + { type: "finish", reason: "stop" }, + ]) + }), + ) + + it.effect("preserves encrypted reasoning metadata for continuation", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide( + fixedResponse( + sseEvents( + { type: "response.reasoning_summary_text.delta", item_id: "rs_1", delta: "thinking" }, + { + type: "response.output_item.done", + item: { + type: "reasoning", + id: "rs_1", + encrypted_content: "encrypted-state", + summary: [{ type: "summary_text", text: "thinking" }], + }, + }, + { type: "response.completed", response: { id: "resp_1" } }, + ), + ), + ), + ) + + expect(response.events).toContainEqual( + expect.objectContaining({ + type: "reasoning-end", + id: "rs_1", + providerMetadata: { openai: { itemId: "rs_1", reasoningEncryptedContent: "encrypted-state" } }, + }), + ) + }), + ) + + it.effect("continues a stateless reasoning conversation", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate( + LLM.request({ + id: "req_reasoning_continue", + model, + messages: [ + Message.user("What changed?"), + Message.assistant([ + { + type: "reasoning", + text: "Checked the previous diff.", + providerMetadata: { + openai: { + itemId: "rs_1", + reasoningEncryptedContent: "encrypted-state", + }, + }, + }, + { type: "text", text: "The parser changed." }, + ]), + Message.user("Summarize it."), + ], + }), + ).pipe( + Effect.provide( + dynamicResponse((input) => + Effect.gen(function* () { + const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie) + expect(yield* Effect.promise(() => web.json())).toMatchObject({ + input: [ + { role: "user", content: [{ type: "input_text", text: "What changed?" }] }, + { + type: "reasoning", + id: "rs_1", + encrypted_content: "encrypted-state", + summary: [{ type: "summary_text", text: "Checked the previous diff." }], + }, + { role: "assistant", content: [{ type: "output_text", text: "The parser changed." }] }, + { role: "user", content: [{ type: "input_text", text: "Summarize it." }] }, + ], + }) + return input.respond( + sseEvents( + { type: "response.output_text.delta", item_id: "msg_1", delta: "Parser now round-trips reasoning." }, + { type: "response.completed", response: { id: "resp_1" } }, + ), + { headers: { "content-type": "text/event-stream" } }, + ) + }), + ), + ), + ) + + expect(response.text).toBe("Parser now round-trips reasoning.") + }), + ) + + it.effect("preserves assistant content order around reasoning items", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_reasoning_order", + model, + messages: [ + Message.assistant([ + { type: "text", text: "Before." }, + { + type: "reasoning", + text: "Checked order.", + providerMetadata: { + openai: { + itemId: "rs_1", + reasoningEncryptedContent: "encrypted-state", + }, + }, + }, + { type: "text", text: "After." }, + ]), + ], + }), + ) + + expect(prepared.body.input).toEqual([ + { role: "assistant", content: [{ type: "output_text", text: "Before." }] }, + { + type: "reasoning", + id: "rs_1", + encrypted_content: "encrypted-state", + summary: [{ type: "summary_text", text: "Checked order." }], + }, + { role: "assistant", content: [{ type: "output_text", text: "After." }] }, + ]) + }), + ) + + it.effect("skips non-persisted reasoning ids without encrypted state", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_reasoning_without_encrypted_state", + model, + messages: [ + Message.user("What changed?"), + Message.assistant([ + { + type: "reasoning", + text: "Checked the previous diff.", + providerMetadata: { + openai: { + itemId: "rs_1", + reasoningEncryptedContent: null, + }, + }, + }, + { type: "text", text: "The parser changed." }, + ]), + Message.user("Summarize it."), + ], + providerOptions: { openai: { store: false } }, + }), + ) + + expect(prepared.body).toMatchObject({ + input: [ + { role: "user", content: [{ type: "input_text", text: "What changed?" }] }, + { role: "assistant", content: [{ type: "output_text", text: "The parser changed." }] }, + { role: "user", content: [{ type: "input_text", text: "Summarize it." }] }, + ], + store: false, + }) + }), + ) + it.effect("assembles streamed function call input", () => Effect.gen(function* () { const body = sseEvents( @@ -532,17 +838,36 @@ describe("OpenAI Responses route", () => { }), ) + it.effect("lowers user image content", () => + Effect.gen(function* () { + const prepared = yield* LLMClient.prepare( + LLM.request({ + id: "req_media", + model, + messages: [Message.user({ type: "media", mediaType: "image/png", data: "AAECAw==" })], + }), + ) + + expect(prepared.body.input).toEqual([ + { + role: "user", + content: [{ type: "input_image", image_url: "data:image/png;base64,AAECAw==" }], + }, + ]) + }), + ) + it.effect("rejects unsupported user media content", () => Effect.gen(function* () { const error = yield* LLMClient.prepare( LLM.request({ id: "req_media", model, - messages: [Message.user({ type: "media", mediaType: "image/png", data: "AAECAw==" })], + messages: [Message.user({ type: "media", mediaType: "application/pdf", data: "AAECAw==" })], }), ).pipe(Effect.flip) - expect(error.message).toContain("OpenAI Responses user messages only support text content for now") + expect(error.message).toContain("OpenAI Responses user media content only supports images") }), ) @@ -552,7 +877,11 @@ describe("OpenAI Responses route", () => { Effect.provide(fixedResponse(sseEvents({ type: "error", code: "rate_limit_exceeded", message: "Slow down" }))), ) - expect(response.events).toEqual([{ type: "provider-error", message: "Slow down" }]) + // Prefix the code so consumers see the failure mode, not just the + // sometimes-generic provider message. The bare message alone meant + // production errors like rate limits were indistinguishable from + // unrelated stream failures. + expect(response.events).toEqual([{ type: "provider-error", message: "rate_limit_exceeded: Slow down" }]) }), ) @@ -566,6 +895,99 @@ describe("OpenAI Responses route", () => { }), ) + it.effect("falls back to error code when message is empty", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide(fixedResponse(sseEvents({ type: "error", code: "internal_error", message: "" }))), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "internal_error" }]) + }), + ) + + // Regression: `response.failed` carries the failure details under + // `response.error`, not at the top level. The previous handler only + // checked top-level `message`/`code` and so always emitted the bare + // "OpenAI Responses response failed" string, hiding the real cause. + it.effect("surfaces response.failed details from response.error", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide( + fixedResponse( + sseEvents({ + type: "response.failed", + response: { + id: "resp_failed_1", + error: { code: "server_error", message: "Upstream model unavailable" }, + }, + }), + ), + ), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "server_error: Upstream model unavailable" }]) + }), + ) + + it.effect("surfaces response.failed code when no nested message is present", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide( + fixedResponse( + sseEvents({ + type: "response.failed", + response: { id: "resp_failed_2", error: { code: "invalid_prompt" } }, + }), + ), + ), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "invalid_prompt" }]) + }), + ) + + it.effect("surfaces error event details even when they arrive nested under response.error", () => + Effect.gen(function* () { + // Some OpenAI-compatible proxies and older SDK versions wrap the + // top-level error fields into a nested `response.error` payload + // when they bubble up an HTTP error as an SSE `error` event. Honour + // both shapes so the user still sees the underlying cause instead + // of the catch-all string. + const response = yield* LLMClient.generate(request).pipe( + Effect.provide( + fixedResponse( + sseEvents({ + type: "error", + response: { error: { code: "context_length_exceeded", message: "prompt too long" } }, + }), + ), + ), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "context_length_exceeded: prompt too long" }]) + }), + ) + + it.effect("falls back to a stable default when both error and response are absent", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide(fixedResponse(sseEvents({ type: "error" }))), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "OpenAI Responses stream error" }]) + }), + ) + + it.effect("falls back to a stable default when response.failed has no error payload", () => + Effect.gen(function* () { + const response = yield* LLMClient.generate(request).pipe( + Effect.provide(fixedResponse(sseEvents({ type: "response.failed", response: { id: "resp_failed_3" } }))), + ) + + expect(response.events).toEqual([{ type: "provider-error", message: "OpenAI Responses response failed" }]) + }), + ) + it.effect("fails HTTP provider errors before stream parsing", () => Effect.gen(function* () { const error = yield* LLMClient.generate(request).pipe( diff --git a/packages/llm/test/provider/openrouter.test.ts b/packages/llm/test/provider/openrouter.test.ts index b3fb6bddc7..86d1317b3e 100644 --- a/packages/llm/test/provider/openrouter.test.ts +++ b/packages/llm/test/provider/openrouter.test.ts @@ -8,15 +8,14 @@ import { it } from "../lib/effect" describe("OpenRouter", () => { it.effect("prepares OpenRouter models through the OpenAI-compatible Chat route", () => Effect.gen(function* () { - const model = OpenRouter.model("openai/gpt-4o-mini", { apiKey: "test-key" }) + const model = OpenRouter.configure({ apiKey: "test-key" }).model("openai/gpt-4o-mini") expect(model).toMatchObject({ id: "openai/gpt-4o-mini", provider: "openrouter", - route: "openrouter", - baseURL: "https://openrouter.ai/api/v1", - apiKey: "test-key", + route: { id: "openrouter" }, }) + expect(model.route.endpoint.baseURL).toBe("https://openrouter.ai/api/v1") const prepared = yield* LLMClient.prepare(LLM.request({ model, prompt: "Say hello." })) @@ -33,7 +32,8 @@ describe("OpenRouter", () => { Effect.gen(function* () { const prepared = yield* LLMClient.prepare( LLM.request({ - model: OpenRouter.model("anthropic/claude-3.7-sonnet:thinking", { + model: OpenRouter.configure({ + apiKey: "test-key", providerOptions: { openrouter: { usage: true, @@ -41,7 +41,7 @@ describe("OpenRouter", () => { promptCacheKey: "session_123", }, }, - }), + }).model("anthropic/claude-3.7-sonnet:thinking"), prompt: "Think briefly.", }), ) diff --git a/packages/llm/test/recorded-golden.ts b/packages/llm/test/recorded-golden.ts index 6a6c8c7ac9..76568ca671 100644 --- a/packages/llm/test/recorded-golden.ts +++ b/packages/llm/test/recorded-golden.ts @@ -1,8 +1,8 @@ import type { HttpRecorder } from "@opencode-ai/http-recorder" -import { describe, type TestOptions } from "bun:test" +import { describe } from "bun:test" import { Effect } from "effect" -import type { ModelRef } from "../src" -import { goldenScenarioTags, runGoldenScenario, type GoldenScenarioID } from "./recorded-scenarios" +import type { Model } from "../src" +import { goldenScenarioTags, goldenScenarioTitle, runGoldenScenario, type GoldenScenarioID } from "./recorded-scenarios" import { recordedTests } from "./recorded-test" import { kebab } from "./recorded-utils" @@ -17,12 +17,12 @@ type ScenarioInput = readonly tags?: ReadonlyArray readonly maxTokens?: number readonly temperature?: number | false - readonly timeout?: number | TestOptions + readonly timeout?: number } type TargetInput = { readonly name: string - readonly model: ModelRef + readonly model: Model readonly protocol?: string readonly requires?: ReadonlyArray readonly transport?: Transport @@ -35,22 +35,16 @@ type TargetInput = { const scenarioInput = (input: ScenarioInput) => (typeof input === "string" ? { id: input } : input) -const scenarioTitle = (id: GoldenScenarioID) => { - if (id === "text") return "streams text" - if (id === "tool-call") return "streams tool call" - return "drives a tool loop" -} - const defaultPrefix = (target: TargetInput) => { if (target.prefix) return target.prefix const transport = target.transport === "websocket" ? "-websocket" : "" - return `${target.model.provider}-${target.protocol ?? target.model.route}${transport}` + return `${target.model.provider}-${target.protocol ?? target.model.route.id}${transport}` } const metadata = (target: TargetInput) => ({ provider: target.model.provider, protocol: target.protocol, - route: target.model.route, + route: target.model.route.id, transport: target.transport ?? "http", model: target.model.id, ...target.metadata, @@ -75,7 +69,7 @@ const runTarget = (target: TargetInput) => { describe(`${target.name} recorded`, () => { target.scenarios.forEach((raw) => { const input = scenarioInput(raw) - const name = input.name ?? scenarioTitle(input.id) + const name = input.name ?? goldenScenarioTitle(input.id) recorded.effect.with( name, { diff --git a/packages/llm/test/recorded-scenarios.ts b/packages/llm/test/recorded-scenarios.ts index 3af7a77608..eca97ee655 100644 --- a/packages/llm/test/recorded-scenarios.ts +++ b/packages/llm/test/recorded-scenarios.ts @@ -1,6 +1,17 @@ import { expect } from "bun:test" import { Effect, Schema, Stream } from "effect" -import { LLM, LLMEvent, LLMResponse, ToolChoice, ToolDefinition, type LLMRequest, type ModelRef } from "../src" +import { + LLM, + LLMEvent, + LLMResponse, + Message, + ToolChoice, + ToolDefinition, + type ContentPart, + type FinishReason, + type LLMRequest, + type Model, +} from "../src" import { LLMClient } from "../src/route" import { tool } from "../src/tool" @@ -39,48 +50,9 @@ export const weatherRuntimeTool = tool({ ), }) -export const textRequest = (input: { - readonly id: string - readonly model: ModelRef - readonly prompt?: string - readonly maxTokens?: number - readonly temperature?: number | false -}) => - LLM.request({ - id: input.id, - model: input.model, - system: "You are concise.", - prompt: input.prompt ?? "Reply with exactly: Hello!", - cache: "none", - generation: - input.temperature === false - ? { maxTokens: input.maxTokens ?? 20 } - : { maxTokens: input.maxTokens ?? 20, temperature: input.temperature ?? 0 }, - }) - -export const weatherToolRequest = (input: { - readonly id: string - readonly model: ModelRef - readonly maxTokens?: number - readonly temperature?: number | false -}) => - LLM.request({ - id: input.id, - model: input.model, - system: "Call tools exactly as requested.", - prompt: "Call get_weather with city exactly Paris.", - tools: [weatherTool], - toolChoice: ToolChoice.make(weatherTool), - cache: "none", - generation: - input.temperature === false - ? { maxTokens: input.maxTokens ?? 80 } - : { maxTokens: input.maxTokens ?? 80, temperature: input.temperature ?? 0 }, - }) - export const weatherToolLoopRequest = (input: { readonly id: string - readonly model: ModelRef + readonly model: Model readonly system?: string readonly maxTokens?: number readonly temperature?: number | false @@ -99,7 +71,7 @@ export const weatherToolLoopRequest = (input: { export const goldenWeatherToolLoopRequest = (input: { readonly id: string - readonly model: ModelRef + readonly model: Model readonly maxTokens?: number readonly temperature?: number | false }) => @@ -108,6 +80,12 @@ export const goldenWeatherToolLoopRequest = (input: { system: "Use the get_weather tool exactly once. After the tool result, reply exactly: Paris is sunny.", }) +const RESTROOM_IMAGE_TEXT = "jiggling restroom prison" +const restroomImage = () => + Effect.promise(() => Bun.file(new URL("./fixtures/media/restroom.png", import.meta.url)).bytes()).pipe( + Effect.map((bytes) => Buffer.from(bytes).toString("base64")), + ) + export const runWeatherToolLoop = (request: LLMRequest) => LLMClient.stream({ request, @@ -158,54 +136,253 @@ export const expectGoldenWeatherToolLoop = (events: ReadonlyArray) => expect(LLMResponse.text({ events }).trim()).toMatch(/^Paris is sunny\.?$/) } -export type GoldenScenarioID = "text" | "tool-call" | "tool-loop" - export interface GoldenScenarioContext { readonly id: string - readonly model: ModelRef + readonly model: Model readonly maxTokens?: number readonly temperature?: number | false } const generate = (request: LLMRequest) => LLMClient.generate(request) -export const goldenScenarioTags = (id: GoldenScenarioID) => { - if (id === "text") return ["text", "golden"] - if (id === "tool-call") return ["tool", "tool-call", "golden"] - return ["tool", "tool-loop", "golden"] +const generation = (context: GoldenScenarioContext, maxTokens: number) => + context.temperature === false ? { maxTokens } : { maxTokens, temperature: context.temperature ?? 0 } + +const normalizeImageText = (value: string) => + value + .toLowerCase() + .replace(/[^a-z\s]/g, "") + .replace(/\s+/g, " ") + .trim() + +const encryptedReasoningOptions = { + openai: { + store: false, + includeEncryptedReasoning: true, + reasoningEffort: "low", + reasoningSummary: "auto", + }, +} as const + +type AssistantTextExpectation = string | RegExp + +type UserStep = { readonly type: "user"; readonly content: Message.ContentInput } +type AssistantStep = { + readonly type: "assistant" + readonly text?: AssistantTextExpectation + readonly toolCall?: { readonly name: string; readonly input: unknown } + readonly reasoning?: "openai-encrypted" + readonly id?: string + readonly system?: string + readonly maxTokens?: number + readonly finish?: FinishReason + readonly tools?: LLM.RequestInput["tools"] + readonly toolChoice?: LLM.RequestInput["toolChoice"] + readonly providerOptions?: LLMRequest["providerOptions"] + readonly assert?: (response: LLMResponse) => void +} +type ConversationStep = UserStep | AssistantStep + +const user = (content: Message.ContentInput): ConversationStep => ({ type: "user", content }) + +const assistant = { + expectText: ( + text: AssistantTextExpectation, + options?: Omit, + ): ConversationStep => ({ type: "assistant", text, ...options }), + expectToolCall: ( + name: string, + input: unknown, + options?: Omit, + ): ConversationStep => ({ type: "assistant", toolCall: { name, input }, finish: "tool-calls", ...options }), + expectEncryptedReasoningText: ( + text: AssistantTextExpectation, + options?: Omit, + ): ConversationStep => ({ + type: "assistant", + text, + reasoning: "openai-encrypted", + providerOptions: encryptedReasoningOptions, + ...options, + }), } -export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioContext) => +const assertAssistantText = (actual: string, expected: AssistantTextExpectation) => { + if (typeof expected === "string") { + expect(actual.trim()).toBe(expected) + return + } + expect(actual.trim()).toMatch(expected) +} + +const assertAssistantToolCall = (response: LLMResponse, expected: NonNullable) => { + expect(response.toolCalls).toMatchObject([ + { type: "tool-call", id: expect.any(String), name: expected.name, input: expected.input }, + ]) +} + +// The generated golden scenarios only model one assistant shape at a time: +// encrypted reasoning + text, text, or tool call. Keep mixed interleavings in +// focused protocol tests where event order can be asserted directly. +const assistantMessageFromResponse = (response: LLMResponse, step: AssistantStep) => { + const content: ContentPart[] = [] + if (step.reasoning === "openai-encrypted") { + const reasoning = response.events.find( + (event): event is Extract => + LLMEvent.is.reasoningEnd(event) && typeof event.providerMetadata?.openai?.itemId === "string", + ) + if (!reasoning) throw new Error("OpenAI Responses did not return reasoning metadata") + expect(reasoning.providerMetadata?.openai?.reasoningEncryptedContent).toEqual(expect.any(String)) + content.push({ type: "reasoning", text: response.reasoning, providerMetadata: reasoning.providerMetadata }) + } + + if (response.text.length > 0) content.push({ type: "text", text: response.text }) + content.push(...response.toolCalls) + return Message.assistant(content) +} + +const runGeneratedConversation = (context: GoldenScenarioContext, steps: ReadonlyArray) => Effect.gen(function* () { - if (id === "text") { + const messages: Message[] = [] + let generated = 0 + for (const step of steps) { + if (step.type === "user") { + messages.push(Message.user(step.content)) + continue + } + + generated += 1 const response = yield* generate( - textRequest({ - id: context.id, + LLM.request({ + id: step.id ? `${context.id}_${step.id}` : `${context.id}_${generated}`, model: context.model, - prompt: "Reply exactly with: Hello!", - maxTokens: context.maxTokens ?? 40, - temperature: context.temperature, + system: step.system, + cache: "none", + messages, + tools: step.tools, + toolChoice: step.toolChoice, + providerOptions: step.providerOptions, + generation: generation(context, step.maxTokens ?? context.maxTokens ?? 80), }), ) - expect(response.text.trim()).toMatch(/^Hello!?$/) - expectFinish(response.events, "stop") - return + if (step.text !== undefined) assertAssistantText(response.text, step.text) + if (step.toolCall) assertAssistantToolCall(response, step.toolCall) + step.assert?.(response) + expectFinish(response.events, step.finish ?? "stop") + messages.push(assistantMessageFromResponse(response, step)) } + }) - if (id === "tool-call") { - const response = yield* generate( - weatherToolRequest({ - id: context.id, - model: context.model, - maxTokens: context.maxTokens ?? 80, - temperature: context.temperature, - }), - ) - expectWeatherToolCall(response) - expectFinish(response.events, "tool-calls") - return - } +const runTextScenario = (context: GoldenScenarioContext) => + runGeneratedConversation(context, [ + user("Reply exactly with: Hello!"), + assistant.expectText(/^Hello!?$/, { + system: "You are concise.", + maxTokens: context.maxTokens ?? 40, + providerOptions: + context.model.route.id === "gemini" ? { gemini: { thinkingConfig: { thinkingBudget: 0 } } } : undefined, + }), + ]) +const runToolCallScenario = (context: GoldenScenarioContext) => + runGeneratedConversation(context, [ + user("Call get_weather with city exactly Paris."), + assistant.expectToolCall( + weatherToolName, + { city: "Paris" }, + { + system: "Call tools exactly as requested.", + tools: [weatherTool], + toolChoice: ToolChoice.make(weatherTool), + maxTokens: context.maxTokens ?? 80, + }, + ), + ]) + +const runImageScenario = (context: GoldenScenarioContext) => + Effect.gen(function* () { + yield* runGeneratedConversation(context, [ + user([ + { + type: "text", + text: "The image contains exactly three lowercase English words. Read them left to right and reply with only those words.", + }, + { type: "media", mediaType: "image/png", data: yield* restroomImage() }, + ]), + assistant.expectText(/.+/, { + system: "Read images carefully. Reply only with the visible text.", + maxTokens: context.maxTokens ?? 20, + assert: (response) => expect(normalizeImageText(response.text)).toBe(RESTROOM_IMAGE_TEXT), + }), + ]) + }) + +// Reproduces a tool-result image round trip: a tool returns image bytes, and +// the next model turn must receive provider-native image content instead of a +// JSON-stringified base64 blob. +const screenshotToolName = "read_screenshot" +const runImageToolResultScenario = (context: GoldenScenarioContext) => + Effect.gen(function* () { + const image = yield* restroomImage() + const response = yield* generate( + LLM.request({ + id: `${context.id}_image_tool_result`, + model: context.model, + system: "Read images carefully. Reply only with the visible text, lowercase, no punctuation.", + cache: "none", + generation: generation(context, context.maxTokens ?? 40), + messages: [ + Message.user("Use the read_screenshot tool, then reply with the words shown."), + Message.assistant([{ type: "tool-call", id: "call_screenshot_1", name: screenshotToolName, input: {} }]), + Message.tool({ + id: "call_screenshot_1", + name: screenshotToolName, + resultType: "content", + result: [ + { type: "text", text: "Image read successfully" }, + { type: "media", mediaType: "image/png", data: image }, + ], + }), + ], + tools: [ + ToolDefinition.make({ + name: screenshotToolName, + description: "Capture a screenshot of the current screen.", + inputSchema: { type: "object", properties: {}, additionalProperties: false }, + }), + ], + }), + ) + + expectFinish(response.events, "stop") + expect(normalizeImageText(response.text)).toBe(RESTROOM_IMAGE_TEXT) + }) + +const runReasoningScenario = (context: GoldenScenarioContext) => + runGeneratedConversation(context, [ + user("Think briefly, then reply exactly with: Hello!"), + assistant.expectText(/^Hello!?$/, { + system: "Show concise reasoning when the provider supports visible reasoning summaries.", + providerOptions: { openai: { reasoningEffort: "low", reasoningSummary: "auto" } }, + maxTokens: context.maxTokens ?? 120, + assert: (response) => expect(response.usage?.reasoningTokens ?? 0).toBeGreaterThan(0), + }), + ]) + +const runReasoningContinuationScenario = (context: GoldenScenarioContext) => + runGeneratedConversation(context, [ + user("Think briefly, then reply exactly with: Hello!"), + assistant.expectEncryptedReasoningText(/^Hello!?$/, { + id: "first", + system: "Show concise reasoning when the provider supports visible reasoning summaries.", + maxTokens: context.maxTokens ?? 120, + }), + user("Now reply exactly with: Done."), + assistant.expectText(/^Done\.?$/, { id: "second", maxTokens: 40, providerOptions: encryptedReasoningOptions }), + ]) + +const runToolLoopScenario = (context: GoldenScenarioContext) => + Effect.gen(function* () { expectGoldenWeatherToolLoop( yield* runWeatherToolLoop( goldenWeatherToolLoopRequest({ @@ -218,6 +395,30 @@ export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioC ) }) +const goldenScenarios = { + text: { title: "streams text", tags: ["text", "golden"], run: runTextScenario }, + "tool-call": { title: "streams tool call", tags: ["tool", "tool-call", "golden"], run: runToolCallScenario }, + "tool-loop": { title: "drives a tool loop", tags: ["tool", "tool-loop", "golden"], run: runToolLoopScenario }, + image: { title: "reads image text", tags: ["media", "image", "vision", "golden"], run: runImageScenario }, + "image-tool-result": { + title: "reads image returned from tool result", + tags: ["media", "image", "vision", "tool", "tool-result", "golden"], + run: runImageToolResultScenario, + }, + reasoning: { title: "uses reasoning", tags: ["reasoning", "golden"], run: runReasoningScenario }, + "reasoning-continuation": { + title: "continues encrypted reasoning", + tags: ["reasoning", "continuation", "encrypted-reasoning", "golden"], + run: runReasoningContinuationScenario, + }, +} as const + +export type GoldenScenarioID = keyof typeof goldenScenarios +export const goldenScenarioTitle = (id: GoldenScenarioID) => goldenScenarios[id].title +export const goldenScenarioTags = (id: GoldenScenarioID) => [...goldenScenarios[id].tags] +export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioContext) => + goldenScenarios[id].run(context) + const usageSummary = (usage: LLMResponse["usage"] | undefined) => { if (!usage) return undefined return Object.fromEntries( @@ -235,7 +436,7 @@ const usageSummary = (usage: LLMResponse["usage"] | undefined) => { const pushText = (summary: Array>, type: "text" | "reasoning", value: string) => { const last = summary.at(-1) if (last?.type === type) { - last.value = `${last.value ?? ""}${value}` + last.value = `${typeof last.value === "string" ? last.value : ""}${value}` return } summary.push({ type, value }) diff --git a/packages/llm/test/recorded-test.ts b/packages/llm/test/recorded-test.ts index 62e51337d9..bbc8b93da6 100644 --- a/packages/llm/test/recorded-test.ts +++ b/packages/llm/test/recorded-test.ts @@ -69,8 +69,6 @@ export const recordedTests = (options: RecordedTestsOptions) => requestExecutor, webSocketCassetteLayer(cassette, { metadata: recorderMetadata, mode }), ) - return Layer.mergeAll(deps, LLMClient.layerWithWebSocket.pipe(Layer.provide(deps))).pipe( - Layer.provide(cassetteService), - ) + return Layer.mergeAll(deps, LLMClient.layer.pipe(Layer.provide(deps))).pipe(Layer.provide(cassetteService)) }, }) diff --git a/packages/llm/test/route.test.ts b/packages/llm/test/route.test.ts new file mode 100644 index 0000000000..681583bc9e --- /dev/null +++ b/packages/llm/test/route.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, test } from "bun:test" +import * as OpenAIChat from "../src/protocols/openai-chat" +import { Auth } from "../src/route" + +describe("Route.with", () => { + test("merges endpoint query and header defaults while replacing auth and id", () => { + const auth = Auth.headers({ "x-auth": "new" }) + const route = OpenAIChat.route + .with({ + id: "base-chat", + endpoint: { + baseURL: "https://api.example.test/v1", + query: { keep: "base", base: "1" }, + }, + headers: { "x-base": "base", "x-override": "base" }, + auth: Auth.headers({ "x-auth": "old" }), + }) + .with({ + id: "patched-chat", + endpoint: { query: { keep: "patch", patch: "1" } }, + headers: { "x-override": "patch", "x-patch": "patch" }, + auth, + }) + + expect(route.id).toBe("patched-chat") + expect(route.auth).toBe(auth) + expect(route.endpoint).toMatchObject({ + baseURL: "https://api.example.test/v1", + path: "/chat/completions", + query: { keep: "patch", base: "1", patch: "1" }, + }) + expect(route.defaults.headers).toEqual({ + "x-base": "base", + "x-override": "patch", + "x-patch": "patch", + }) + expect(route.defaults.http?.headers).toEqual({ + "x-base": "base", + "x-override": "patch", + "x-patch": "patch", + }) + }) +}) diff --git a/packages/llm/test/schema.test.ts b/packages/llm/test/schema.test.ts index 01d6fadd9f..3c6628c2e5 100644 --- a/packages/llm/test/schema.test.ts +++ b/packages/llm/test/schema.test.ts @@ -1,16 +1,19 @@ import { describe, expect, test } from "bun:test" import { Schema } from "effect" -import { ContentPart, LLMEvent, LLMRequest, ModelID, ModelLimits, ModelRef, ProviderID, Usage } from "../src/schema" +import * as OpenAIChat from "../src/protocols/openai-chat" +import * as OpenAIResponses from "../src/protocols/openai-responses" +import { ContentPart, LLMEvent, LLMRequest, Model, ModelID, ProviderID, Usage } from "../src/schema" import { ProviderShared } from "../src/protocols/shared" -const model = new ModelRef({ +const model = new Model({ id: ModelID.make("fake-model"), provider: ProviderID.make("fake-provider"), - route: "openai-chat", - baseURL: "https://fake.local", - limits: new ModelLimits({}), + route: OpenAIChat.route, }) +const decodeLLMRequest = Schema.decodeUnknownSync(LLMRequest as unknown as Schema.Decoder) +const decodeLLMEvent = Schema.decodeUnknownSync(LLMEvent as unknown as Schema.Decoder) + describe("llm schema", () => { test("decodes a minimal request", () => { const input: unknown = { @@ -22,26 +25,26 @@ describe("llm schema", () => { generation: {}, } - const decoded = Schema.decodeUnknownSync(LLMRequest)(input) + const decoded = decodeLLMRequest(input) expect(decoded.id).toBe("req_1") expect(decoded.messages[0]?.content[0]?.type).toBe("text") }) test("accepts custom route ids", () => { - const decoded = Schema.decodeUnknownSync(LLMRequest)({ - model: { ...model, route: "custom-route" }, + const decoded = decodeLLMRequest({ + model: Model.update(model, { route: OpenAIResponses.route }), system: [], messages: [], tools: [], generation: {}, }) - expect(decoded.model.route).toBe("custom-route") + expect(decoded.model.route.id).toBe("openai-responses") }) test("rejects invalid event type", () => { - expect(() => Schema.decodeUnknownSync(LLMEvent)({ type: "bogus" })).toThrow() + expect(() => decodeLLMEvent({ type: "bogus" })).toThrow() }) test("finish constructors accept usage input", () => { diff --git a/packages/llm/test/tool-runtime.test.ts b/packages/llm/test/tool-runtime.test.ts index 81389a466b..2733debe42 100644 --- a/packages/llm/test/tool-runtime.test.ts +++ b/packages/llm/test/tool-runtime.test.ts @@ -1,7 +1,7 @@ import { describe, expect } from "bun:test" import { Effect, Schema, Stream } from "effect" import { GenerationOptions, LLM, LLMEvent, LLMRequest, LLMResponse, ToolChoice } from "../src" -import { LLMClient } from "../src/route" +import { Auth, LLMClient } from "../src/route" import * as AnthropicMessages from "../src/protocols/anthropic-messages" import * as OpenAIChat from "../src/protocols/openai-chat" import { tool, ToolFailure, type ToolExecuteContext } from "../src/tool" @@ -12,11 +12,9 @@ import { dynamicResponse, scriptedResponses } from "./lib/http" import { deltaChunk, finishChunk, toolCallChunk } from "./lib/openai-chunks" import { sseEvents } from "./lib/sse" -const model = OpenAIChat.model({ - id: "gpt-4o-mini", - baseURL: "https://api.openai.test/v1/", - headers: { authorization: "Bearer test" }, -}) +const model = OpenAIChat.route + .with({ endpoint: { baseURL: "https://api.openai.test/v1/" }, auth: Auth.bearer("test") }) + .model({ id: "gpt-4o-mini" }) const Json = Schema.fromJsonString(Schema.Unknown) const decodeJson = Schema.decodeUnknownSync(Json) @@ -141,6 +139,45 @@ describe("LLMClient tools", () => { }), ) + it.effect("preserves content tool results from dynamic tools", () => + Effect.gen(function* () { + const screenshot = tool({ + description: "Capture a screenshot.", + jsonSchema: { type: "object", properties: {} }, + execute: () => + Effect.succeed({ + type: "content" as const, + value: [ + { type: "text" as const, text: "Screenshot captured." }, + { type: "media" as const, mediaType: "image/png", data: "AAAA" }, + ], + }), + }) + + const events = Array.from( + yield* LLMClient.stream({ request: baseRequest, tools: { screenshot } }).pipe( + Stream.runCollect, + Effect.provide( + scriptedResponses([sseEvents(toolCallChunk("call_1", "screenshot", "{}"), finishChunk("tool_calls"))]), + ), + ), + ) + + expect(events.find(LLMEvent.is.toolResult)).toMatchObject({ + type: "tool-result", + id: "call_1", + name: "screenshot", + result: { + type: "content", + value: [ + { type: "text", text: "Screenshot captured." }, + { type: "media", mediaType: "image/png", data: "AAAA" }, + ], + }, + }) + }), + ) + it.effect("executes tool calls for one step without looping by default", () => Effect.gen(function* () { const layer = scriptedResponses([ @@ -249,7 +286,9 @@ describe("LLMClient tools", () => { yield* TestToolRuntime.runTools({ request: LLM.updateRequest(baseRequest, { - model: AnthropicMessages.model({ id: "claude-sonnet-4-5", apiKey: "test" }), + model: AnthropicMessages.route + .with({ auth: Auth.header("x-api-key", "test") }) + .model({ id: "claude-sonnet-4-5" }), }), tools: { get_weather }, }).pipe(Stream.runCollect, Effect.provide(layer)) @@ -496,7 +535,9 @@ describe("LLMClient tools", () => { const events = Array.from( yield* TestToolRuntime.runTools({ request: LLM.updateRequest(baseRequest, { - model: AnthropicMessages.model({ id: "claude-sonnet-4-5", apiKey: "test" }), + model: AnthropicMessages.route + .with({ auth: Auth.header("x-api-key", "test") }) + .model({ id: "claude-sonnet-4-5" }), }), tools: {}, }).pipe(Stream.runCollect, Effect.provide(layer)), diff --git a/packages/llm/test/tool.types.ts b/packages/llm/test/tool.types.ts index 4ffc30c986..1fce9fd231 100644 --- a/packages/llm/test/tool.types.ts +++ b/packages/llm/test/tool.types.ts @@ -1,10 +1,11 @@ import { Effect, Schema } from "effect" import { LLM } from "../src" import * as OpenAIChat from "../src/protocols/openai-chat" +import { Auth } from "../src/route" import { tool } from "../src/tool" const request = LLM.request({ - model: OpenAIChat.model({ id: "gpt-4o-mini", apiKey: "fixture" }), + model: OpenAIChat.route.with({ auth: Auth.bearer("fixture") }).model({ id: "gpt-4o-mini" }), prompt: "Use the tool.", }) diff --git a/packages/opencode/.gitignore b/packages/opencode/.gitignore index 6600814a8c..932b09924c 100644 --- a/packages/opencode/.gitignore +++ b/packages/opencode/.gitignore @@ -3,8 +3,6 @@ dist dist-* gen app.log -src/provider/models-snapshot.js -src/provider/models-snapshot.d.ts script/build-*.ts temporary-*.md .artifacts diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 84a880dc51..9d8101371a 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.42", + "version": "7.3.46", "name": "@kilocode/cli", "type": "module", "license": "MIT", @@ -10,6 +10,8 @@ "test": "bun run script/test-runner.ts", "test:ci": "bun run script/test-runner.ts --ci", "test:httpapi": "bun run script/httpapi-exercise.ts --mode coverage --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode auth --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode effect --fail-on-missing --fail-on-skip", + "bench:test": "bun run script/bench-test-suite.ts", + "profile:test": "bun run script/profile-test-files.ts", "build": "bun run script/build.ts", "fix-node-pty": "bun run script/fix-node-pty.ts", "dev": "bun run --conditions=browser ./src/index.ts", @@ -69,7 +71,8 @@ "vscode-languageserver-types": "3.17.5", "why-is-node-running": "3.2.2", "zod-to-json-schema": "3.24.5", - "@types/npmcli__arborist": "6.3.3" + "@types/npmcli__arborist": "6.3.3", + "@opencode-ai/http-recorder": "workspace:*" }, "dependencies": { "@actions/core": "1.11.1", @@ -79,7 +82,7 @@ "@ai-sdk/amazon-bedrock": "4.0.96", "@ai-sdk/anthropic": "3.0.71", "@ai-sdk/azure": "3.0.49", - "@ai-sdk/cerebras": "2.0.41", + "@ai-sdk/cerebras": "2.0.54", "@ai-sdk/cohere": "3.0.27", "@ai-sdk/deepinfra": "2.0.41", "@ai-sdk/gateway": "3.0.104", @@ -88,13 +91,13 @@ "@ai-sdk/groq": "3.0.31", "@ai-sdk/mistral": "3.0.27", "@ai-sdk/openai": "3.0.53", - "@ai-sdk/openai-compatible": "2.0.41", + "@ai-sdk/openai-compatible": "2.0.48", "@ai-sdk/perplexity": "3.0.26", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@ai-sdk/togetherai": "2.0.41", "@ai-sdk/vercel": "2.0.39", - "@ai-sdk/xai": "3.0.82", + "@ai-sdk/xai": "3.0.92", "@aws-sdk/credential-providers": "3.1025.0", "@clack/prompts": "1.0.0-alpha.1", "@effect/opentelemetry": "catalog:", @@ -121,7 +124,7 @@ "@openauthjs/openauth": "catalog:", "@opencode-ai/script": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@openrouter/ai-sdk-provider": "2.8.1", + "@openrouter/ai-sdk-provider": "2.9.0", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", @@ -153,7 +156,7 @@ "drizzle-orm": "catalog:", "effect": "catalog:", "fuzzysort": "3.1.0", - "gitlab-ai-provider": "6.6.0", + "gitlab-ai-provider": "6.7.0", "glob": "13.0.5", "google-auth-library": "10.5.0", "gray-matter": "4.0.3", @@ -193,7 +196,8 @@ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", "yargs": "18.0.0", "zod": "catalog:", - "zod-to-json-schema": "3.24.5" + "zod-to-json-schema": "3.24.5", + "@opencode-ai/llm": "workspace:*" }, "overrides": { "drizzle-orm": "catalog:" diff --git a/packages/opencode/parsers-config.ts b/packages/opencode/parsers-config.ts index 9bcb9e85c7..2f5e3e0bef 100644 --- a/packages/opencode/parsers-config.ts +++ b/packages/opencode/parsers-config.ts @@ -296,5 +296,81 @@ export default { ], }, }, + { + filetype: "elixir", + wasm: "https://github.com/elixir-lang/tree-sitter-elixir/releases/download/v0.3.5/tree-sitter-elixir.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/elixir/highlights.scm", + ], + locals: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/elixir/locals.scm", + ], + }, + }, + { + filetype: "fsharp", + wasm: "https://github.com/ionide/tree-sitter-fsharp/releases/download/0.3.0/tree-sitter-fsharp.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/fsharp/highlights.scm", + ], + }, + }, + { + filetype: "r", + wasm: "https://github.com/r-lib/tree-sitter-r/releases/download/v1.2.0/tree-sitter-r.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/r/highlights.scm", + ], + locals: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/r/locals.scm", + ], + }, + }, + { + filetype: "make", + aliases: ["makefile"], + wasm: "https://github.com/tree-sitter-grammars/tree-sitter-make/releases/download/v1.1.1/tree-sitter-make.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/make/highlights.scm", + ], + }, + }, + { + filetype: "vim", + wasm: "https://github.com/tree-sitter-grammars/tree-sitter-vim/releases/download/v0.8.1/tree-sitter-vim.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/vim/highlights.scm", + ], + locals: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/vim/locals.scm", + ], + }, + }, + { + filetype: "xml", + wasm: "https://github.com/tree-sitter-grammars/tree-sitter-xml/releases/download/v0.7.0/tree-sitter-xml.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/xml/highlights.scm", + ], + locals: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/xml/locals.scm", + ], + }, + }, + { + filetype: "agda", + wasm: "https://github.com/tree-sitter/tree-sitter-agda/releases/download/v1.3.3/tree-sitter-agda.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/agda/highlights.scm", + ], + }, + }, ], } diff --git a/packages/opencode/script/bench-test-suite.ts b/packages/opencode/script/bench-test-suite.ts new file mode 100644 index 0000000000..27ff7750c2 --- /dev/null +++ b/packages/opencode/script/bench-test-suite.ts @@ -0,0 +1,52 @@ +// Full-suite timing harness for the test-speed research in ../../perf/test-suite.md. +// Use this for periodic sanity checks; use profile-test-files.ts for discovery. +// Env: BENCH_WARMUPS=0 BENCH_RUNS=1 bun run bench:test +const warmups = Number(Bun.env.BENCH_WARMUPS ?? 0) +const runs = Number(Bun.env.BENCH_RUNS ?? 1) +const timings: number[] = [] + +if (!Number.isInteger(warmups) || warmups < 0) { + console.error("BENCH_WARMUPS must be a non-negative integer") + process.exit(1) +} +if (!Number.isInteger(runs) || runs < 1) { + console.error("BENCH_RUNS must be a positive integer") + process.exit(1) +} + +for (const index of Array.from({ length: warmups + runs }, (_, index) => index)) { + const measured = index >= warmups + const label = measured ? `run ${index - warmups + 1}/${runs}` : `warmup ${index + 1}/${warmups}` + const start = performance.now() + console.log(`bench:test ${label}`) + + const proc = Bun.spawn(["bun", "test", "--timeout", "30000"], { + cwd: import.meta.dir + "/..", + stdout: "inherit", + stderr: "inherit", + env: Bun.env, + }) + + const exitCode = await proc.exited + if (exitCode !== 0) { + console.error(`bench:test failed during ${label} with exit code ${exitCode}`) + process.exit(exitCode) + } + + const seconds = (performance.now() - start) / 1000 + console.log(`bench:test ${label} ${seconds.toFixed(3)}s`) + if (measured) timings.push(seconds) +} + +const sorted = timings.toSorted((a, b) => a - b) +const median = sorted[Math.floor(sorted.length / 2)] +const mean = timings.reduce((sum, timing) => sum + timing, 0) / timings.length +const best = sorted[0] ?? median +const worst = sorted.at(-1) ?? median + +console.log( + `bench:test median=${median.toFixed(3)}s mean=${mean.toFixed(3)}s best=${best.toFixed(3)}s worst=${worst.toFixed(3)}s`, +) +console.log(`METRIC test_suite_seconds=${median.toFixed(3)}`) +console.log(`METRIC test_suite_best_seconds=${best.toFixed(3)}`) +console.log(`METRIC test_suite_worst_seconds=${worst.toFixed(3)}`) diff --git a/packages/opencode/script/build-node.ts b/packages/opencode/script/build-node.ts index 515c6733db..8c471d7bae 100755 --- a/packages/opencode/script/build-node.ts +++ b/packages/opencode/script/build-node.ts @@ -11,7 +11,7 @@ const dir = path.resolve(__dirname, "..") process.chdir(dir) -await import("./generate.ts") +const generated = await import("./generate.ts") // Load migrations from migration directories const migrationDirs = ( @@ -52,6 +52,7 @@ await Bun.build({ external: ["jsonc-parser", "@lydell/node-pty"], define: { KILO_MIGRATIONS: JSON.stringify(migrations), + KILO_MODELS_DEV: generated.modelsData, KILO_CHANNEL: `'${Script.channel}'`, }, files: { diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 1a5f4fe51f..6f374fea68 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -12,7 +12,7 @@ const dir = path.resolve(__dirname, "..") process.chdir(dir) -await import("./generate.ts") +const generated = await import("./generate.ts") import { Script } from "@opencode-ai/script" import pkg from "../package.json" @@ -58,7 +58,7 @@ const createEmbeddedWebUIBundle = async () => { console.log(`Building Web UI to embed in the binary`) const appDir = path.join(import.meta.dirname, "../../app") const dist = path.join(appDir, "dist") - await $`bun run --cwd ${appDir} build` + await $`KILO_CHANNEL=${Script.channel} bun run --cwd ${appDir} build` const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: dist }))) .map((file) => file.replaceAll("\\", "/")) .filter((file) => !file.endsWith(".map")) @@ -218,6 +218,7 @@ for (const item of targets) { define: { KILO_VERSION: `'${Script.version}'`, KILO_MIGRATIONS: JSON.stringify(migrations), + KILO_MODELS_DEV: generated.modelsData, OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + workerRelativePath, KILO_WORKER_PATH: workerPath, KILO_CHANNEL: `'${Script.channel}'`, diff --git a/packages/opencode/script/generate.ts b/packages/opencode/script/generate.ts index bef990e2e8..e3b9f3156b 100644 --- a/packages/opencode/script/generate.ts +++ b/packages/opencode/script/generate.ts @@ -8,16 +8,7 @@ const dir = path.resolve(__dirname, "..") process.chdir(dir) const modelsUrl = process.env.KILO_MODELS_URL || "https://models.dev" -// Fetch and generate models.dev snapshot -const modelsData = process.env.MODELS_DEV_API_JSON +export const modelsData = process.env.MODELS_DEV_API_JSON ? await Bun.file(process.env.MODELS_DEV_API_JSON).text() : await fetch(`${modelsUrl}/api.json`).then((x) => x.text()) -await Bun.write( - path.join(dir, "../core/src/models-snapshot.js"), - `// @ts-nocheck\n// Auto-generated by build.ts - do not edit\nexport const snapshot = ${modelsData}\n`, -) -await Bun.write( - path.join(dir, "../core/src/models-snapshot.d.ts"), - `// Auto-generated by build.ts - do not edit\nexport declare const snapshot: Record\n`, -) -console.log("Generated models-snapshot.js") +console.log("Loaded models.dev snapshot") diff --git a/packages/opencode/script/profile-test-files.ts b/packages/opencode/script/profile-test-files.ts new file mode 100644 index 0000000000..12b9bccd84 --- /dev/null +++ b/packages/opencode/script/profile-test-files.ts @@ -0,0 +1,42 @@ +// Per-file profiler for finding candidate test-speed work; see ../../perf/test-suite.md +// for the benchmark notes, kept wins, and discarded experiments. +// Example: TEST_PROFILE_GLOB='test/server/**/*.test.ts' TEST_PROFILE_TOP=15 bun run profile:test +const pattern = Bun.env.TEST_PROFILE_GLOB ?? "test/**/*.test.{ts,tsx}" +const limit = Number(Bun.env.TEST_PROFILE_LIMIT ?? 0) +const timeout = Bun.env.TEST_PROFILE_TIMEOUT ?? "30000" +const files = Array.fromAsync(new Bun.Glob(pattern).scan({ cwd: import.meta.dir + "/..", onlyFiles: true })) + .then((files) => files.toSorted()) + .then((files) => (limit > 0 ? files.slice(0, limit) : files)) + +const results = [] +for (const file of await files) { + const start = performance.now() + const proc = Bun.spawn(["bun", "test", "--timeout", timeout, file], { + cwd: import.meta.dir + "/..", + stdout: "pipe", + stderr: "pipe", + env: Bun.env, + }) + const [output, error, exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]) + const seconds = (performance.now() - start) / 1000 + results.push({ file, seconds, exitCode }) + console.log(`${exitCode === 0 ? "PASS" : "FAIL"} ${seconds.toFixed(3)}s ${file}`) + if (exitCode !== 0) console.log((output + error).trim()) +} + +const sorted = results.toSorted((a, b) => b.seconds - a.seconds) +console.log("\nSlowest test files:") +for (const result of sorted.slice(0, Number(Bun.env.TEST_PROFILE_TOP ?? 20))) { + console.log(`${result.seconds.toFixed(3)}s ${result.exitCode === 0 ? "PASS" : "FAIL"} ${result.file}`) +} + +if (sorted[0]) { + console.log(`METRIC slowest_test_file_seconds=${sorted[0].seconds.toFixed(3)}`) + console.log(`METRIC profiled_test_files=${results.length}`) +} + +if (results.some((result) => result.exitCode !== 0)) process.exit(1) diff --git a/packages/opencode/specs/tui-plugins.md b/packages/opencode/specs/tui-plugins.md index f583642666..cf45689baf 100644 --- a/packages/opencode/specs/tui-plugins.md +++ b/packages/opencode/specs/tui-plugins.md @@ -230,6 +230,7 @@ Top-level API groups exposed to `tui(api, options, meta)`: - `api.attention.notify(input)` - `api.keys.formatSequence(parts)`, `formatBindings(bindings)` - `api.keymap` +- `api.mode.current()`, `api.mode.push(mode)` - `api.route.register(routes)` / `api.route.navigate(name, params?)` / `api.route.current` - `api.ui.Dialog`, `DialogAlert`, `DialogConfirm`, `DialogPrompt`, `DialogSelect`, `Slot`, `Prompt`, `ui.toast`, `ui.dialog` - `api.tuiConfig` @@ -255,6 +256,68 @@ Top-level API groups exposed to `tui(api, options, meta)`: - Disposers returned by `api.keymap` registrations and `acquireResource(...)` are automatically cleaned up when the plugin deactivates. You do not need to add those disposers to `api.lifecycle.onDispose(...)` yourself. - Built-in which-key shortcuts are resolved from flat `keybinds` command ids such as `which_key_toggle`, not plugin options. +#### Mode-aware layers + +OpenCode registers a `mode` layer field on the host keymap. Plugins can use it to keep bindings active only in the relevant UI state. + +Built-in modes: + +- `base`: normal app, route, and prompt interaction. +- `modal`: host dialog stack is open, including dialogs rendered through `api.ui.dialog` and `api.ui.Dialog*` components. +- `autocomplete`: host prompt autocomplete is open. +- `api.mode.current()` returns the active top mode, or `base` when no pushed mode is active. + +Example: register a command and shortcut that are active only in normal app mode: + +```tsx +api.keymap.registerLayer({ + mode: "base", + commands: [ + { + name: "demo.open", + title: "Demo", + category: "Plugin", + namespace: "palette", + run() { + api.route.navigate("demo") + }, + }, + ], + bindings: [{ key: "ctrl+shift+m", cmd: "demo.open", desc: "Open demo" }], +}) +``` + +Layers without `mode` are not mode-gated and can remain active while dialogs or autocomplete are open. Use that only for intentionally global commands or low-level keymap extensions. + +Plugins that own a full-screen route or modal-like UI can temporarily push a plugin-specific mode with `api.mode.push(...)`. Use a plugin-scoped mode name. The returned disposer pops that specific stack entry and is idempotent, so popping an older mode while a newer mode is on top leaves the newer mode active. + +```tsx +import { onCleanup } from "solid-js" + +api.route.register([ + { + name: "demo", + render: () => { + const popMode = api.mode.push("acme.demo") + onCleanup(popMode) + + return ( + + demo + + ) + }, + }, +]) + +api.keymap.registerLayer({ + mode: "acme.demo", + bindings: [{ key: "escape", cmd: () => api.route.navigate("home"), desc: "Close demo" }], +}) +``` + +Mode pushes are automatically tracked by the plugin runtime. If a plugin is disabled, fails during activation, or the TUI shuts down before the plugin calls the disposer, OpenCode pops the plugin's pushed modes during plugin cleanup. Calling the disposer yourself is still recommended for component lifetimes; cleanup remains idempotent. + ### Keys - `api.keys` exposes host-formatted shortcut display helpers for plugin UI. diff --git a/packages/opencode/src/account/account.ts b/packages/opencode/src/account/account.ts index a0aed88cba..dcff82664b 100644 --- a/packages/opencode/src/account/account.ts +++ b/packages/opencode/src/account/account.ts @@ -1,4 +1,5 @@ import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, Context } from "effect" +import { serviceUse } from "@/effect/service-use" import { FetchHttpClient, HttpClient, @@ -181,6 +182,8 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Account") {} +export const use = serviceUse(Service) + export const layer: Layer.Layer = Layer.effect( Service, Effect.gen(function* () { diff --git a/packages/opencode/src/account/repo.ts b/packages/opencode/src/account/repo.ts index 04380137c8..a5291e8283 100644 --- a/packages/opencode/src/account/repo.ts +++ b/packages/opencode/src/account/repo.ts @@ -1,4 +1,5 @@ import { eq } from "drizzle-orm" +import { serviceUse } from "@/effect/service-use" import { Effect, Layer, Option, Schema, Context } from "effect" import { Database } from "@/storage/db" @@ -38,6 +39,8 @@ export interface Interface { export class Service extends Context.Service()("@opencode/AccountRepo") {} +export const use = serviceUse(Service) + export const layer: Layer.Layer = Layer.effect( Service, Effect.gen(function* () { diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 849a522597..c50a89e372 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -42,9 +42,7 @@ import type { ACPConfig } from "./types" import { ACPRuntime } from "./runtime" import { Provider } from "@/provider/provider" import { ModelID, ProviderID } from "../provider/schema" -import { Installation } from "@/installation" import { MessageV2 } from "@/session/message-v2" -import { Config } from "@/config/config" import { ConfigMCP } from "@/config/mcp" import { Todo } from "@/session/todo" import { Result, Schema } from "effect" diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index ce6cf30b6d..f7e2c134a3 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -1,4 +1,5 @@ import { Config } from "@/config/config" +import { serviceUse } from "@/effect/service-use" import { Provider } from "@/provider/provider" import { ModelID, ProviderID } from "../provider/schema" import { generateObject, streamObject, type ModelMessage } from "ai" @@ -68,7 +69,7 @@ export interface Interface { whenToUse: string systemPrompt: string }, - Provider.ModelNotFoundError + Provider.DefaultModelError > } @@ -76,6 +77,8 @@ type State = Omit export class Service extends Context.Service()("@opencode/Agent") {} +export const use = serviceUse(Service) + export const layer = Layer.effect( Service, Effect.gen(function* () { diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index 5c4685f5ec..b5f4320bda 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -5,6 +5,7 @@ import { BusEvent } from "./bus-event" import { GlobalBus } from "./global" import { InstanceState } from "@/effect/instance-state" import { makeRuntime } from "@/effect/run-service" +import { serviceUse } from "@/effect/service-use" import { Identifier } from "@/id/id" import type { InstanceContext } from "@/project/instance-context" import { InstanceRef } from "@/effect/instance-ref" @@ -37,8 +38,16 @@ export interface Interface { properties: BusProperties, options?: { id?: string }, ) => Effect.Effect - readonly subscribe: (def: D) => Stream.Stream> - readonly subscribeAll: () => Stream.Stream + // subscribe / subscribeAll are eager: the underlying PubSub subscription is + // acquired in the caller's Scope at `yield*` time. Any publish after the + // yield is delivered, even if stream consumption starts later. The previous + // Stream-returning shape acquired the subscription lazily on first pull, + // opening a race window during which publishes were lost — see + // test/bus/bus-effect.test.ts RACE tests. + readonly subscribe: ( + def: D, + ) => Effect.Effect>, never, Scope.Scope> + readonly subscribeAll: () => Effect.Effect, never, Scope.Scope> readonly subscribeCallback: ( def: D, callback: (event: Payload) => unknown, @@ -48,6 +57,8 @@ export interface Interface { export class Service extends Context.Service()("@opencode/Bus") {} +export const use = serviceUse(Service) + export const layer = Layer.effect( Service, Effect.gen(function* () { @@ -109,26 +120,26 @@ export const layer = Layer.effect( }) } - function subscribe(def: D): Stream.Stream> { - log.info("subscribing", { type: def.type }) - return Stream.unwrap( - Effect.gen(function* () { - const s = yield* InstanceState.get(state) - const ps = yield* getOrCreate(s, def) - return Stream.fromPubSub(ps) - }), - ).pipe(Stream.ensuring(Effect.sync(() => log.info("unsubscribing", { type: def.type })))) - } + const subscribe = ( + def: D, + ): Effect.Effect>, never, Scope.Scope> => + Effect.gen(function* () { + log.info("subscribing", { type: def.type }) + const s = yield* InstanceState.get(state) + const ps = yield* getOrCreate(s, def) + const subscription = yield* PubSub.subscribe(ps) + yield* Effect.addFinalizer(() => Effect.sync(() => log.info("unsubscribing", { type: def.type }))) + return Stream.fromSubscription(subscription) + }) - function subscribeAll(): Stream.Stream { - log.info("subscribing", { type: "*" }) - return Stream.unwrap( - Effect.gen(function* () { - const s = yield* InstanceState.get(state) - return Stream.fromPubSub(s.wildcard) - }), - ).pipe(Stream.ensuring(Effect.sync(() => log.info("unsubscribing", { type: "*" })))) - } + const subscribeAll = (): Effect.Effect, never, Scope.Scope> => + Effect.gen(function* () { + log.info("subscribing", { type: "*" }) + const s = yield* InstanceState.get(state) + const subscription = yield* PubSub.subscribe(s.wildcard) + yield* Effect.addFinalizer(() => Effect.sync(() => log.info("unsubscribing", { type: "*" }))) + return Stream.fromSubscription(subscription) + }) function on(pubsub: PubSub.PubSub, type: string, callback: (event: T) => unknown) { return Effect.gen(function* () { diff --git a/packages/opencode/src/cli/cmd/account.ts b/packages/opencode/src/cli/cmd/account.ts index e0755577b6..b9cbf5569c 100644 --- a/packages/opencode/src/cli/cmd/account.ts +++ b/packages/opencode/src/cli/cmd/account.ts @@ -15,6 +15,8 @@ const dim = (value: string) => UI.Style.TEXT_DIM + value + UI.Style.TEXT_NORMAL const activeSuffix = (isActive: boolean) => (isActive ? dim(" (active)") : "") +export const defaultConsoleUrl = "https://console.opencode.ai" + export const formatAccountLabel = (account: { email: string; url: string }, isActive: boolean) => `${account.email} ${dim(account.url)}${activeSuffix(isActive)}` @@ -173,18 +175,17 @@ const openEffect = Effect.fn("open")(function* () { }) export const LoginCommand = effectCmd({ - command: "login ", + command: "login [url]", describe: false, instance: false, builder: (yargs) => yargs.positional("url", { describe: "server URL", type: "string", - demandOption: true, }), handler: Effect.fn("Cli.account.login")(function* (args) { UI.empty() - yield* Effect.orDie(loginEffect(args.url)) + yield* Effect.orDie(loginEffect(args.url ?? defaultConsoleUrl)) }), }) diff --git a/packages/opencode/src/cli/cmd/debug/agent.ts b/packages/opencode/src/cli/cmd/debug/agent.ts index ac9879ff89..c74c1c9079 100644 --- a/packages/opencode/src/cli/cmd/debug/agent.ts +++ b/packages/opencode/src/cli/cmd/debug/agent.ts @@ -1,6 +1,6 @@ import { EOL } from "os" import { basename } from "path" -import { Effect } from "effect" +import { Cause, Effect } from "effect" import { Agent } from "../../../agent/agent" import { Provider } from "@/provider/provider" import { Session } from "@/session/session" @@ -80,7 +80,21 @@ const run = Effect.fn("Cli.debug.agent.body")(function* ( const getAvailableTools = Effect.fn("Cli.debug.agent.getAvailableTools")(function* (agent: Agent.Info) { const provider = yield* Provider.Service const registry = yield* ToolRegistry.Service - const model = agent.model ?? (yield* provider.defaultModel()) + const model = + agent.model ?? + (yield* provider.defaultModel().pipe( + Effect.matchCauseEffect({ + onSuccess: Effect.succeed, + onFailure: (cause) => { + const error = Cause.squash(cause) as Provider.DefaultModelError + if (error instanceof Provider.ModelNotFoundError) { + return fail(`Model not found: ${error.providerID}/${error.modelID}`) + } + if (error instanceof Provider.NoModelsError) return fail(`No models found for provider ${error.providerID}`) + return fail("No providers found") + }, + }), + )) return yield* registry.tools({ ...model, agent }) }) @@ -133,7 +147,20 @@ const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(functio ? agent.model : yield* Effect.gen(function* () { const provider = yield* Provider.Service - return yield* provider.defaultModel() + return yield* provider.defaultModel().pipe( + Effect.matchCauseEffect({ + onSuccess: Effect.succeed, + onFailure: (cause) => { + const error = Cause.squash(cause) as Provider.DefaultModelError + if (error instanceof Provider.ModelNotFoundError) { + return fail(`Model not found: ${error.providerID}/${error.modelID}`) + } + if (error instanceof Provider.NoModelsError) + return fail(`No models found for provider ${error.providerID}`) + return fail("No providers found") + }, + }), + ) }) const now = Date.now() const message: MessageV2.Assistant = { diff --git a/packages/opencode/src/cli/cmd/debug/v2.ts b/packages/opencode/src/cli/cmd/debug/v2.ts index 836f581367..56866a0e02 100644 --- a/packages/opencode/src/cli/cmd/debug/v2.ts +++ b/packages/opencode/src/cli/cmd/debug/v2.ts @@ -1,18 +1,16 @@ import { EOL } from "os" -import { Effect, Layer, Option } from "effect" +import { Effect, Option } from "effect" import { Catalog } from "@opencode-ai/core/catalog" import { LocationServiceMap } from "@opencode-ai/core/location-layer" import { PluginBoot } from "@opencode-ai/core/plugin/boot" import { effectCmd } from "../../effect-cmd" -const Runtime = Layer.mergeAll(LocationServiceMap.layer) - export const V2Command = effectCmd({ command: "v2", describe: "debug v2 catalog and built-in plugins", instance: false, - handler: Effect.fn("Cli.debug.v2")( - function* () { + handler: () => + Effect.gen(function* () { yield* PluginBoot.Service.use((service) => service.wait()) const catalog = yield* Catalog.Service const providers = (yield* catalog.provider.available()).sort((a, b) => a.id.localeCompare(b.id)) @@ -35,12 +33,13 @@ export const V2Command = effectCmd({ ), } process.stdout.write(JSON.stringify(result, null, 2) + EOL) - }, - Effect.provide( - LocationServiceMap.get({ - directory: process.cwd(), - }), + }).pipe( + Effect.withSpan("Cli.debug.v2"), + Effect.provide( + LocationServiceMap.get({ + directory: process.cwd(), + }), + ), + Effect.provide(LocationServiceMap.layer), ), - Effect.provide(Runtime), - ), }) diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index 1a374d2a23..9ac605f46f 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -19,7 +19,7 @@ import type { import { UI } from "../ui" import { cmd } from "./cmd" import { effectCmd } from "../effect-cmd" -import { ModelsDev } from "@opencode-ai/core/models" +import { ModelsDev } from "@opencode-ai/core/models-dev" import { InstanceRef } from "@/effect/instance-ref" import { SessionShare } from "@/share/session" import { Session } from "@/session/session" diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index e35a0488a0..296c08fd98 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -7,8 +7,10 @@ import { SessionTable, MessageTable, PartTable } from "../../session/session.sql import { InstanceRef } from "@/effect/instance-ref" import { ShareNext } from "@/share/share-next" import { EOL } from "os" +import path from "path" import { AppFileSystem } from "@opencode-ai/core/filesystem" import { Effect, Schema } from "effect" +import type { InstanceContext } from "@/project/instance-context" const decodeMessageInfo = Schema.decodeUnknownSync(MessageV2.Info) const decodePart = Schema.decodeUnknownSync(MessageV2.Part) @@ -89,11 +91,11 @@ export const ImportCommand = effectCmd({ handler: Effect.fn("Cli.import")(function* (args) { const ctx = yield* InstanceRef if (!ctx) return yield* Effect.die("InstanceRef not provided") - return yield* runImport(args.file, ctx.project.id) + return yield* runImport(args.file, ctx) }), }) -const runImport = Effect.fn("Cli.import.body")(function* (file: string, projectID: string) { +const runImport = Effect.fn("Cli.import.body")(function* (file: string, ctx: InstanceContext) { const share = yield* ShareNext.Service const fs = yield* AppFileSystem.Service @@ -168,14 +170,19 @@ const runImport = Effect.fn("Cli.import.body")(function* (file: string, projectI const info = Schema.decodeUnknownSync(Session.Info)({ ...exportData.info, - projectID, + projectID: ctx.project.id, + directory: ctx.directory, + path: path.relative(path.resolve(ctx.worktree), ctx.directory).replaceAll("\\", "/"), }) as Session.Info const row = Session.toRow(info) Database.use((db) => db .insert(SessionTable) .values(row) - .onConflictDoUpdate({ target: SessionTable.id, set: { project_id: row.project_id } }) + .onConflictDoUpdate({ + target: SessionTable.id, + set: { project_id: row.project_id, directory: row.directory, path: row.path }, + }) .run(), ) diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts index 2ae7cece6a..f7ea030aa9 100644 --- a/packages/opencode/src/cli/cmd/mcp.ts +++ b/packages/opencode/src/cli/cmd/mcp.ts @@ -12,7 +12,6 @@ import { McpOAuthProvider } from "../../mcp/oauth-provider" import { Config } from "@/config/config" import { ConfigMCP } from "../../config/mcp" import { InstanceRef } from "@/effect/instance-ref" -import { Installation } from "../../installation" import { InstallationVersion } from "@opencode-ai/core/installation/version" import path from "path" import { Global } from "@opencode-ai/core/global" diff --git a/packages/opencode/src/cli/cmd/models.ts b/packages/opencode/src/cli/cmd/models.ts index 08203ba21e..909b0b40ba 100644 --- a/packages/opencode/src/cli/cmd/models.ts +++ b/packages/opencode/src/cli/cmd/models.ts @@ -2,7 +2,7 @@ import { EOL } from "os" import { Effect } from "effect" import { Provider } from "@/provider/provider" import { ProviderID } from "../../provider/schema" -import { ModelsDev } from "@opencode-ai/core/models" +import { ModelsDev } from "@opencode-ai/core/models-dev" import { effectCmd, fail } from "../effect-cmd" import { UI } from "../ui" diff --git a/packages/opencode/src/cli/cmd/providers.ts b/packages/opencode/src/cli/cmd/providers.ts index e88a56f6c6..3e45862a25 100644 --- a/packages/opencode/src/cli/cmd/providers.ts +++ b/packages/opencode/src/cli/cmd/providers.ts @@ -3,7 +3,7 @@ import { cmd } from "./cmd" import { CliError, effectCmd, fail } from "../effect-cmd" import { UI } from "../ui" import * as Prompt from "../effect/prompt" -import { ModelsDev } from "@opencode-ai/core/models" +import { ModelsDev } from "@opencode-ai/core/models-dev" import { map, pipe, sortBy, values } from "remeda" import path from "path" diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 1373b340da..c4b4a94760 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -218,6 +218,15 @@ export const RunCommand = effectCmd({ type: "boolean", describe: "show thinking blocks", }) + .option("replay", { + type: "boolean", + default: false, + describe: "replay visible session history on interactive resume", + }) + .option("replay-limit", { + type: "number", + describe: "cap visible interactive replay to the newest N messages", + }) .option("interactive", { alias: ["i"], type: "boolean", @@ -269,6 +278,21 @@ export const RunCommand = effectCmd({ die("--interactive cannot be used with --format json") } + if (args.replay && !args.interactive) { + die("--replay requires --interactive") + } + + if (args["replay-limit"] !== undefined && !args.interactive) { + die("--replay-limit requires --interactive") + } + + if ( + args["replay-limit"] !== undefined && + (!Number.isInteger(args["replay-limit"]) || args["replay-limit"] <= 0) + ) { + die("--replay-limit must be a positive integer") + } + if (args.interactive && !process.stdout.isTTY) { die("--interactive requires a TTY stdout") } @@ -281,6 +305,8 @@ export const RunCommand = effectCmd({ } } + const replay = args.replay || args["replay-limit"] !== undefined + const root = Filesystem.resolve(process.env.PWD ?? process.cwd()) const directory = (() => { if (!args.dir) return args.attach ? undefined : root @@ -432,7 +458,7 @@ export const RunCommand = effectCmd({ const name = title() const result = await sdk.session.create({ title: name, - permission: rules, + permission: [...rules], }) const id = result.data?.id if (!id) { @@ -475,7 +501,7 @@ export const RunCommand = effectCmd({ variant: input.variant, } : undefined, - permission: rules, + permission: [...rules], }) const id = result.data?.id if (!id) { @@ -786,6 +812,8 @@ export const RunCommand = effectCmd({ sessionID, sessionTitle: sess.title, resume: Boolean(args.session || args.continue) && !args.fork, + replay, + replayLimit: args["replay-limit"], agent, model, variant: args.variant, @@ -821,6 +849,8 @@ export const RunCommand = effectCmd({ agent: args.agent, model, variant: args.variant, + replay, + replayLimit: args["replay-limit"], files, initialInput, thinking, diff --git a/packages/opencode/src/cli/cmd/run/footer.command.tsx b/packages/opencode/src/cli/cmd/run/footer.command.tsx index 4da370eabe..cf6822c066 100644 --- a/packages/opencode/src/cli/cmd/run/footer.command.tsx +++ b/packages/opencode/src/cli/cmd/run/footer.command.tsx @@ -6,7 +6,7 @@ import { createEffect, createMemo, createSignal, type Accessor } from "solid-js" import { RunFooterMenu, createFooterMenuState, type RunFooterMenuItem } from "./footer.menu" import { formatBindings } from "./keymap.shared" import type { RunFooterTheme } from "./theme" -import type { FooterKeybinds, RunCommand, RunInput, RunProvider } from "./types" +import type { FooterKeybinds, FooterSubagentTab, RunCommand, RunInput, RunProvider } from "./types" type PanelEntry = RunFooterMenuItem & { category: string @@ -15,6 +15,7 @@ type PanelEntry = RunFooterMenuItem & { type CommandEntry = | (PanelEntry & { action: "model" }) + | (PanelEntry & { action: "subagent" }) | (PanelEntry & { action: "variant.cycle" }) | (PanelEntry & { action: "variant.list" }) | (PanelEntry & { action: "slash"; name: string }) @@ -32,11 +33,19 @@ type VariantEntry = PanelEntry & { current: boolean } +type SubagentEntry = PanelEntry & { + sessionID: string + current: boolean +} + type MenuState = ReturnType const PANEL_PAD = 2 const PANEL_LIST_ROWS = 10 -export const RUN_COMMAND_PANEL_ROWS = PANEL_LIST_ROWS + 6 +const PANEL_FRAME_ROWS = 6 +export const RUN_COMMAND_PANEL_ROWS = PANEL_LIST_ROWS + PANEL_FRAME_ROWS +const SUBAGENT_LIST_ROWS = 12 +export const RUN_SUBAGENT_PANEL_ROWS = SUBAGENT_LIST_ROWS + PANEL_FRAME_ROWS const PANEL_PAGE = PANEL_LIST_ROWS - 1 const PANEL_BORDER = { topLeft: "", @@ -89,6 +98,18 @@ function categoryRank(category: string) { return 2 } +function subagentStatusLabel(status: FooterSubagentTab["status"]) { + if (status === "completed") { + return "done" + } + + if (status === "error") { + return "error" + } + + return "running" +} + function handleKey(input: { event: KeyEvent menu: MenuState @@ -273,10 +294,12 @@ function PanelShell(props: { export function RunCommandMenuBody(props: { theme: Accessor commands: Accessor + subagents: Accessor variants: Accessor keybinds: FooterKeybinds onClose: () => void onModel: () => void + onSubagent: () => void onVariant: () => void onVariantCycle: () => void onCommand: (name: string) => void @@ -293,6 +316,20 @@ export function RunCommandMenuBody(props: { category: "Suggested", display: "Switch model", }, + ...(props.subagents().length > 0 + ? [ + { + action: "subagent" as const, + category: "Suggested", + display: "View subagents", + footer: `${props.subagents().length} active`, + keywords: props + .subagents() + .map((item) => `${item.label} ${item.description} ${item.title ?? ""}`) + .join(" "), + }, + ] + : []), { action: "variant.cycle", category: "Suggested", @@ -346,6 +383,11 @@ export function RunCommandMenuBody(props: { return } + if (item.action === "subagent") { + props.onSubagent() + return + } + if (item.action === "variant.cycle") { props.onVariantCycle() return @@ -423,6 +465,101 @@ export function RunCommandMenuBody(props: { ) } +export function RunSubagentSelectBody(props: { + theme: Accessor + tabs: Accessor + current: Accessor + onClose: () => void + onSelect: (sessionID: string) => void + onRows?: (rows: number) => void +}) { + let field: InputRenderable | undefined + const [query, setQuery] = createSignal("") + const entries = createMemo(() => + props.tabs().map((item) => { + const title = item.description || item.title || item.label + return { + category: "", + display: title, + description: title === item.label ? undefined : item.label, + footer: subagentStatusLabel(item.status), + keywords: `${item.label} ${item.description} ${item.title ?? ""} ${item.status}`, + sessionID: item.sessionID, + current: props.current() === item.sessionID, + } + }), + ) + const items = createMemo(() => match(query(), entries())) + const menu = createFooterMenuState({ count: () => items().length, limit: SUBAGENT_LIST_ROWS }) + const select = () => { + const item = items()[menu.selected()] + if (!item) { + return + } + + props.onSelect(item.sessionID) + } + + createEffect(() => { + query() + menu.reset() + }) + + createEffect(() => { + if (query().trim()) { + return + } + + const index = items().findIndex((item) => item.current) + if (index !== -1) { + menu.reveal(index) + } + }) + + createEffect(() => { + props.onRows?.(menu.rows() + PANEL_FRAME_ROWS) + }) + + useKeyboard((event) => { + if (event.defaultPrevented) { + return + } + + handleKey({ event, menu, field: () => field, setQuery, select, close: props.onClose }) + }) + + return ( + { + field = input + }} + onQuery={setQuery} + > + + + ) +} + export function RunVariantSelectBody(props: { theme: Accessor variants: Accessor diff --git a/packages/opencode/src/cli/cmd/run/footer.prompt.tsx b/packages/opencode/src/cli/cmd/run/footer.prompt.tsx index 54f20dbc07..c3f9918acc 100644 --- a/packages/opencode/src/cli/cmd/run/footer.prompt.tsx +++ b/packages/opencode/src/cli/cmd/run/footer.prompt.tsx @@ -7,7 +7,7 @@ /** @jsxImportSource @opentui/solid */ import { pathToFileURL } from "bun" import { StyledText, bg, fg, type KeyBinding, type KeyEvent, type TextareaRenderable } from "@opentui/core" -import { useKeyboard } from "@opentui/solid" +import { useKeyboard, useRenderer } from "@opentui/solid" import fuzzysort from "fuzzysort" import path from "path" import { createEffect, createMemo, createResource, createSignal, onCleanup, onMount, type Accessor } from "solid-js" @@ -66,6 +66,7 @@ type PromptInput = { directory: string findFiles: (query: string) => Promise agents: Accessor + subagents: Accessor resources: Accessor commands: Accessor keybinds: FooterKeybinds @@ -81,6 +82,7 @@ type PromptInput = { onInputClear: () => void onExitRequest?: () => boolean onExit: () => void + onSubagentMenu?: () => void onRows: (rows: number) => void onStatus: (text: string) => void } @@ -88,6 +90,7 @@ type PromptInput = { export type PromptState = { placeholder: Accessor bindings: Accessor + shell: Accessor visible: Accessor options: Accessor selected: Accessor @@ -110,9 +113,14 @@ function clonePrompt(prompt: RunPrompt): RunPrompt { return { text: prompt.text, parts: structuredClone(prompt.parts), + ...(prompt.mode ? { mode: prompt.mode } : {}), } } +function emptyPrompt(shell: boolean): RunPrompt { + return shell ? { text: "", parts: [], mode: "shell" } : { text: "", parts: [] } +} + function removeLineRange(input: string) { const hash = input.lastIndexOf("#") return hash === -1 ? input : input.slice(0, hash) @@ -197,13 +205,45 @@ export function RunPromptBody(props: { onContentChange: () => void bind: (area?: TextareaRenderable) => void }) { + const renderer = useRenderer() let area: TextareaRenderable | undefined + let pasteTick: ReturnType | undefined + + const refreshPasteLayout = () => { + if (pasteTick) { + clearTimeout(pasteTick) + } + + pasteTick = setTimeout(() => { + pasteTick = undefined + if (!area || area.isDestroyed) { + return + } + + // Paste can leave the textarea layout stale until the next edit. + area.getLayoutNode().markDirty() + renderer.requestRender() + void renderer + .idle() + .then(() => { + if (!area || area.isDestroyed) { + return + } + + props.onContentChange() + }) + .catch(() => {}) + }, 0) + } onMount(() => { props.bind(area) }) onCleanup(() => { + if (pasteTick) { + clearTimeout(pasteTick) + } props.bind(undefined) }) @@ -226,6 +266,9 @@ export function RunPromptBody(props: { keyBindings={props.bindings()} onSubmit={props.onSubmit} onKeyDown={props.onKeyDown} + onPaste={() => { + refreshPasteLayout() + }} onContentChange={props.onContentChange} ref={(next) => { area = next @@ -239,7 +282,12 @@ export function RunPromptBody(props: { export function createPromptState(input: PromptInput): PromptState { const keys = createMemo(() => promptKeys(input.keybinds)) const bindings = createMemo(() => keys().bindings) + const [shell, setShell] = createSignal(false) const placeholder = createMemo(() => { + if (shell()) { + return new StyledText([bg(input.theme().surface)(fg(input.theme().muted)('Run a command... "git status"'))]) + } + if (!input.state().first) { return "" } @@ -266,6 +314,11 @@ export function createPromptState(input: PromptInput): PromptState { const [query, setQuery] = createSignal("") const visible = createMemo(() => mode() !== false) + const setShellMode = (value: boolean) => { + setShell(value) + draft = value ? { ...draft, mode: "shell" } : { text: draft.text, parts: structuredClone(draft.parts) } + } + const width = createMemo(() => Math.max(20, input.width() - 8)) const agents = createMemo(() => { return input @@ -542,6 +595,7 @@ export function createPromptState(input: PromptInput): PromptState { const restore = (value: RunPrompt, cursor = Bun.stringWidth(value.text)) => { draft = clonePrompt(value) + setShell(value.mode === "shell") if (!area || area.isDestroyed) { return } @@ -561,7 +615,7 @@ export function createPromptState(input: PromptInput): PromptState { clearParts() hide() - draft = { text: "", parts: [] } + draft = emptyPrompt(shell()) if (!area || area.isDestroyed) { return } @@ -571,7 +625,7 @@ export function createPromptState(input: PromptInput): PromptState { } const replaceDraft = (text: string) => { - draft = { text, parts: [] } + draft = shell() ? { text, parts: [], mode: "shell" } : { text, parts: [] } if (!area || area.isDestroyed) { return } @@ -579,7 +633,7 @@ export function createPromptState(input: PromptInput): PromptState { hide() area.setText(text) clearParts() - draft = { text: area.plainText, parts: [] } + draft = shell() ? { text: area.plainText, parts: [], mode: "shell" } : { text: area.plainText, parts: [] } area.cursorOffset = Math.min(Bun.stringWidth(text), Bun.stringWidth(area.plainText)) scheduleRows() area.focus() @@ -670,10 +724,16 @@ export function createPromptState(input: PromptInput): PromptState { } syncParts() - draft = { - text: area.plainText, - parts: structuredClone(parts), - } + draft = shell() + ? { + text: area.plainText, + parts: structuredClone(parts), + mode: "shell", + } + : { + text: area.plainText, + parts: structuredClone(parts), + } } const push = (value: RunPrompt) => { @@ -908,6 +968,52 @@ export function createPromptState(input: PromptInput): PromptState { } } + if ( + key.name === "!" && + !shell() && + !event.ctrl && + !event.meta && + !event.super && + area && + !area.isDestroyed && + area.cursorOffset === 0 + ) { + event.preventDefault() + setShellMode(true) + return + } + + if (shell() && !visible()) { + if (key.name === "escape") { + event.preventDefault() + setShellMode(false) + return + } + + if (key.name === "backspace" && area && !area.isDestroyed && area.cursorOffset === 0) { + event.preventDefault() + setShellMode(false) + return + } + } + + if ( + key.name === "down" && + !visible() && + !event.ctrl && + !event.meta && + !event.shift && + !event.super && + area && + !area.isDestroyed && + area.plainText.length === 0 && + input.subagents() > 0 + ) { + event.preventDefault() + input.onSubagentMenu?.() + return + } + if (promptHit(keys().clear, key)) { const handled = requestExit() if (handled) { @@ -962,7 +1068,12 @@ export function createPromptState(input: PromptInput): PromptState { return } - if (input.view() === "command" || input.view() === "model" || input.view() === "variant") { + if ( + input.view() === "command" || + input.view() === "model" || + input.view() === "variant" || + input.view() === "subagent-menu" + ) { return } @@ -993,23 +1104,29 @@ export function createPromptState(input: PromptInput): PromptState { return } - if (isExitCommand(next.text)) { + if (next.mode !== "shell" && isExitCommand(next.text)) { input.onExit() return } - const parsed = isNewCommand(next.text) ? undefined : parseSlashCommand(next.text, input.commands()) + const parsed = + next.mode === "shell" || isNewCommand(next.text) ? undefined : parseSlashCommand(next.text, input.commands()) if (parsed?.type === "pending") { input.onStatus("loading commands") return } const submit = parsed?.type === "command" ? { ...next, command: parsed.command } : next + const shellMode = next.mode === "shell" resetDraft() queueMicrotask(async () => { if (await input.onSubmit(submit)) { push(next) + if (shellMode) { + setShellMode(false) + draft = emptyPrompt(false) + } return } @@ -1086,6 +1203,7 @@ export function createPromptState(input: PromptInput): PromptState { return { placeholder, bindings, + shell, visible, options, selected: menu.selected, diff --git a/packages/opencode/src/cli/cmd/run/footer.question.tsx b/packages/opencode/src/cli/cmd/run/footer.question.tsx index 4a0d1f3626..bafb2c4676 100644 --- a/packages/opencode/src/cli/cmd/run/footer.question.tsx +++ b/packages/opencode/src/cli/cmd/run/footer.question.tsx @@ -416,7 +416,7 @@ export function RunQuestionBody(props: { - {hit() ? "✓" : ""} + {hit() ? " ✓" : ""} @@ -466,7 +466,7 @@ export function RunQuestionBody(props: { - {picked() ? "✓" : ""} + {picked() ? " ✓" : ""} = 8 || perTab < 12) { - return `[${slot}]` - } - - const prefix = `[${slot}]` - if (count >= 5 || perTab < 24) { - return prefix - } - - const label = tab.description || tab.title || tab.label - return `${prefix} ${label}` -} - -export function RunFooterSubagentTabs(props: { - tabs: FooterSubagentTab[] - selected?: string - theme: RunFooterTheme - width: number -}) { - const items = mapArray( - () => props.tabs, - (tab, index) => { - const active = () => props.selected === tab.sessionID - const slot = () => String(index() + 1) - return ( - - - {tab.status === "running" ? ( - - - - ) : ( - - {statusIcon(tab.status)} - - )} - - {tabText(tab, slot(), props.tabs.length, props.width)} - - - - ) - }, - ) - - return ( - - - {items()} - - - ) -} - export function RunFooterSubagentBody(props: { active: () => boolean theme: () => RunTheme + tab: () => FooterSubagentTab | undefined + index: () => number + total: () => number detail: () => FooterSubagentDetail | undefined width: () => number diffStyle?: RunDiffStyle @@ -111,6 +48,7 @@ export function RunFooterSubagentBody(props: { }) { const theme = createMemo(() => props.theme()) const footer = createMemo(() => theme().footer) + const tab = createMemo(() => props.tab()) const commits = createMemo(() => props.detail()?.commits ?? []) const opts = createMemo(() => ({ diffStyle: props.diffStyle })) const scrollbar = createMemo(() => ({ @@ -119,6 +57,22 @@ export function RunFooterSubagentBody(props: { foregroundColor: footer().line, }, })) + const title = createMemo(() => { + const current = tab() + if (!current) { + return "" + } + + return current.description || current.title || current.label + }) + const subtitle = createMemo(() => { + const current = tab() + if (!current || title() === current.label) { + return "" + } + + return current.label + }) const rows = indexArray(commits, (commit, index) => ( {index > 0 && separatorRows(commits()[index - 1], commit()) > 0 ? : null} @@ -165,6 +119,32 @@ export function RunFooterSubagentBody(props: { backgroundColor={footer().surface} > + + {(current) => ( + + {current().status === "running" ? ( + + + + ) : ( + + {statusIcon(current().status)} + + )} + + {title()} + 0}> + {" " + subtitle()} + + + 1 && props.index() > 0}> + + {props.index()} of {props.total()} + + + + )} + private setSubagent: (next: FooterSubagentState) => void private promptRoute: FooterPromptRoute = { type: "composer" } - private tabsVisible = false + private subagentMenuRows = SUBAGENT_ROWS private autocomplete = false private interruptTimeout: NodeJS.Timeout | undefined private exitTimeout: NodeJS.Timeout | undefined @@ -553,23 +554,24 @@ export class RunFooter implements FooterApi { // get fixed extra rows; the prompt view scales with textarea line count. private applyHeight(): void { const type = this.view().type - const tabs = this.tabsVisible ? SUBAGENT_TAB_ROWS : 0 const compact = this.promptRoute.type === "composer" && this.autocomplete ? AUTOCOMPLETE_COMPACT_ROWS : 0 - const base = this.base + tabs - compact + const base = this.base - compact const height = type === "permission" ? this.base + PERMISSION_ROWS : type === "question" ? this.base + QUESTION_ROWS : this.promptRoute.type === "command" - ? 1 + tabs + COMMAND_ROWS + ? 1 + COMMAND_ROWS : this.promptRoute.type === "model" - ? 1 + tabs + MODEL_ROWS + ? 1 + MODEL_ROWS : this.promptRoute.type === "variant" - ? 1 + tabs + VARIANT_ROWS - : this.promptRoute.type === "subagent" - ? this.base + tabs + SUBAGENT_INSPECTOR_ROWS - : Math.max(base + TEXTAREA_MIN_ROWS, Math.min(base + PROMPT_MAX_ROWS, base + this.rows)) + ? 1 + VARIANT_ROWS + : this.promptRoute.type === "subagent-menu" + ? 1 + this.subagentMenuRows + : this.promptRoute.type === "subagent" + ? this.base + SUBAGENT_INSPECTOR_ROWS + : Math.max(base + TEXTAREA_MIN_ROWS, Math.min(base + PROMPT_MAX_ROWS, base + this.rows)) if (height !== this.renderer.footerHeight) { this.renderer.footerHeight = height @@ -592,10 +594,10 @@ export class RunFooter implements FooterApi { } } - private syncLayout = (next: { route: FooterPromptRoute; tabs: boolean; autocomplete: boolean }): void => { + private syncLayout = (next: { route: FooterPromptRoute; autocomplete: boolean; subagentRows: number }): void => { this.promptRoute = next.route - this.tabsVisible = next.tabs this.autocomplete = next.autocomplete + this.subagentMenuRows = next.subagentRows if (this.view().type === "prompt") { this.applyHeight() } diff --git a/packages/opencode/src/cli/cmd/run/footer.view.tsx b/packages/opencode/src/cli/cmd/run/footer.view.tsx index e1a028b7e9..affc664b15 100644 --- a/packages/opencode/src/cli/cmd/run/footer.view.tsx +++ b/packages/opencode/src/cli/cmd/run/footer.view.tsx @@ -14,9 +14,15 @@ import { useKeyboard, useTerminalDimensions } from "@opentui/solid" import { Match, Show, Switch, createEffect, createMemo, createSignal, onCleanup } from "solid-js" import "opentui-spinner/solid" import { createColors, createFrames } from "../tui/ui/spinner" -import { RunCommandMenuBody, RunModelSelectBody, RunVariantSelectBody } from "./footer.command" +import { + RUN_SUBAGENT_PANEL_ROWS, + RunCommandMenuBody, + RunModelSelectBody, + RunSubagentSelectBody, + RunVariantSelectBody, +} from "./footer.command" import { FOOTER_MENU_ROWS, RunFooterMenu } from "./footer.menu" -import { RunFooterSubagentBody, RunFooterSubagentTabs } from "./footer.subagent" +import { RunFooterSubagentBody } from "./footer.subagent" import { RunPromptBody, createPromptState, hintFlags } from "./footer.prompt" import { RunPermissionBody } from "./footer.permission" import { RunQuestionBody } from "./footer.question" @@ -85,30 +91,11 @@ type RunFooterViewProps = { onModelSelect: (model: NonNullable) => void onVariantSelect: (variant: string | undefined) => void onRows: (rows: number) => void - onLayout: (input: { route: FooterPromptRoute; tabs: boolean; autocomplete: boolean }) => void + onLayout: (input: { route: FooterPromptRoute; autocomplete: boolean; subagentRows: number }) => void onStatus: (text: string) => void onSubagentSelect?: (sessionID: string | undefined) => void } -function subagentShortcut(event: { - name: string - ctrl?: boolean - meta?: boolean - shift?: boolean - super?: boolean -}): number | undefined { - if (!event.ctrl || event.meta || event.super) { - return undefined - } - - if (!/^[0-9]$/.test(event.name)) { - return undefined - } - - const slot = Number(event.name) - return slot === 0 ? 9 : slot - 1 -} - export { TEXTAREA_MIN_ROWS, TEXTAREA_MAX_ROWS } from "./footer.prompt" export function RunFooterView(props: RunFooterViewProps) { @@ -125,18 +112,39 @@ export function RunFooterView(props: RunFooterViewProps) { ) }) const [route, setRoute] = createSignal({ type: "composer" }) + const [subagentMenuRows, setSubagentMenuRows] = createSignal(RUN_SUBAGENT_PANEL_ROWS) const prompt = createMemo(() => active().type === "prompt" && route().type === "composer") + const selectingSubagent = createMemo(() => active().type === "prompt" && route().type === "subagent-menu") const inspecting = createMemo(() => active().type === "prompt" && route().type === "subagent") const commanding = createMemo(() => active().type === "prompt" && route().type === "command") const modeling = createMemo(() => active().type === "prompt" && route().type === "model") const varianting = createMemo(() => active().type === "prompt" && route().type === "variant") - const panel = createMemo(() => commanding() || modeling() || varianting()) + const panel = createMemo(() => selectingSubagent() || commanding() || modeling() || varianting()) const selected = createMemo(() => { const current = route() return current.type === "subagent" ? current.sessionID : undefined }) const tabs = createMemo(() => subagent().tabs) - const showTabs = createMemo(() => active().type === "prompt" && tabs().length > 0) + const selectedTab = createMemo(() => tabs().find((item) => item.sessionID === selected())) + const selectedIndex = createMemo(() => { + const sessionID = selected() + if (!sessionID) { + return 0 + } + + return tabs().findIndex((item) => item.sessionID === sessionID) + 1 + }) + const subagentIndicator = createMemo(() => { + const count = tabs().length + if (count === 0) { + return + } + + return { + count, + label: count === 1 ? "agent" : "agents", + } + }) const detail = createMemo(() => { const current = route() return current.type === "subagent" ? subagent().details[current.sessionID] : undefined @@ -203,6 +211,15 @@ export function RunFooterView(props: RunFooterViewProps) { props.onSubagentSelect?.(undefined) } + const openSubagentMenu = () => { + if (tabs().length === 0) { + return + } + + setRoute({ type: "subagent-menu" }) + props.onSubagentSelect?.(undefined) + } + const closePanel = () => { setRoute({ type: "composer" }) } @@ -217,16 +234,6 @@ export function RunFooterView(props: RunFooterViewProps) { props.onSubagentSelect?.(undefined) } - const toggleTab = (sessionID: string) => { - const current = route() - if (current.type === "subagent" && current.sessionID === sessionID) { - closeTab() - return - } - - openTab(sessionID) - } - const cycleTab = (dir: -1 | 1) => { if (tabs().length === 0) { return @@ -247,6 +254,7 @@ export function RunFooterView(props: RunFooterViewProps) { directory: props.directory, findFiles: props.findFiles, agents: props.agents, + subagents: () => tabs().length, resources: props.resources, commands: props.commands, keybinds: props.keybinds, @@ -262,9 +270,11 @@ export function RunFooterView(props: RunFooterViewProps) { onInputClear: props.onInputClear, onExitRequest: props.onExitRequest, onExit: props.onExit, + onSubagentMenu: openSubagentMenu, onRows: props.onRows, onStatus: props.onStatus, }) + const shell = createMemo(() => prompt() && composer.shell()) const menu = createMemo(() => prompt() && composer.visible()) createEffect(() => { @@ -300,23 +310,6 @@ export function RunFooterView(props: RunFooterViewProps) { openCommand() }) - useKeyboard((event) => { - if (active().type !== "prompt") { - return - } - - const slot = subagentShortcut(event) - if (slot !== undefined) { - const next = tabs()[slot] - if (!next) { - return - } - - event.preventDefault() - toggleTab(next.sessionID) - } - }) - createEffect(() => { const current = route() if (current.type !== "subagent") { @@ -330,13 +323,30 @@ export function RunFooterView(props: RunFooterViewProps) { closeTab() }) + createEffect(() => { + if (route().type !== "subagent-menu") { + return + } + + if (tabs().length > 0) { + return + } + + closePanel() + }) + createEffect(() => { if (active().type === "prompt") { return } const current = route() - if (current.type !== "command" && current.type !== "model" && current.type !== "variant") { + if ( + current.type !== "command" && + current.type !== "model" && + current.type !== "variant" && + current.type !== "subagent-menu" + ) { return } @@ -346,8 +356,8 @@ export function RunFooterView(props: RunFooterViewProps) { createEffect(() => { props.onLayout({ route: route(), - tabs: tabs().length > 0, autocomplete: menu(), + subagentRows: subagentMenuRows(), }) }) @@ -364,10 +374,6 @@ export function RunFooterView(props: RunFooterViewProps) { > - - - - + + + { props.onCycle() @@ -487,18 +505,20 @@ export function RunFooterView(props: RunFooterViewProps) { paddingTop={1} > - {props.agent} - - - {props.state().model} + {shell() ? "Shell" : props.agent} + + + {props.state().model} + + @@ -570,22 +590,16 @@ export function RunFooterView(props: RunFooterViewProps) { gap={1} flexShrink={0} > - - + 0 || subagentIndicator()}> + - + Press Ctrl-c again to exit - + @@ -601,22 +615,36 @@ export function RunFooterView(props: RunFooterViewProps) { - - - 0}> - - - ▣ - - - - · - - - {duration()} - - + 0}> + + + ▣ + + + + · + + + {duration()} + + + + + + + {(info) => ( + + 0}> + · + + {info().count} {info().label} + · + + to view + + )} + @@ -629,19 +657,30 @@ export function RunFooterView(props: RunFooterViewProps) { flexShrink={0} justifyContent="flex-end" > - 0}> - - {queue()} queued - - - 0}> - - {usage()} - - - 0 && hints().command}> - - {command()} commands + + 0}> + + {queue()} queued + + + 0}> + + {usage()} + + + 0 && hints().command}> + + {command()} commands + + + + } + > + + esc exit shell mode @@ -706,6 +745,9 @@ export function RunFooterView(props: RunFooterViewProps) { tabs().length} detail={detail} width={() => term().width} diffStyle={props.diffStyle} diff --git a/packages/opencode/src/cli/cmd/run/prompt.shared.ts b/packages/opencode/src/cli/cmd/run/prompt.shared.ts index 0da787cb3c..2dda26bae1 100644 --- a/packages/opencode/src/cli/cmd/run/prompt.shared.ts +++ b/packages/opencode/src/cli/cmd/run/prompt.shared.ts @@ -65,11 +65,12 @@ export function promptCopy(prompt: RunPrompt): RunPrompt { return { text: prompt.text, parts: structuredClone(prompt.parts), + ...(prompt.mode ? { mode: prompt.mode } : {}), } } export function promptSame(a: RunPrompt, b: RunPrompt): boolean { - return a.text === b.text && JSON.stringify(a.parts) === JSON.stringify(b.parts) + return a.mode === b.mode && a.text === b.text && JSON.stringify(a.parts) === JSON.stringify(b.parts) } function promptKey(binding: ReturnType[number]): PromptInfo | undefined { diff --git a/packages/opencode/src/cli/cmd/run/runtime.queue.ts b/packages/opencode/src/cli/cmd/run/runtime.queue.ts index d82b9e19e9..79be71cadf 100644 --- a/packages/opencode/src/cli/cmd/run/runtime.queue.ts +++ b/packages/opencode/src/cli/cmd/run/runtime.queue.ts @@ -102,7 +102,7 @@ export async function runPromptQueue(input: QueueInput): Promise { continue } - if (isNewCommand(prompt.text)) { + if (prompt.mode !== "shell" && isNewCommand(prompt.text)) { emit( { type: "queue", @@ -167,9 +167,11 @@ export async function runPromptQueue(input: QueueInput): Promise { break } - const commit = { kind: "user", text: prompt.text, phase: "start", source: "system" } as const - input.trace?.write("ui.commit", commit) - input.footer.append(commit) + if (prompt.mode !== "shell") { + const commit = { kind: "user", text: prompt.text, phase: "start", source: "system" } as const + input.trace?.write("ui.commit", commit) + input.footer.append(commit) + } input.onSend?.(prompt) if (state.closed) { @@ -234,7 +236,7 @@ export async function runPromptQueue(input: QueueInput): Promise { return } - if (isExitCommand(prompt.text)) { + if (prompt.mode !== "shell" && isExitCommand(prompt.text)) { input.footer.close() return } @@ -249,7 +251,7 @@ export async function runPromptQueue(input: QueueInput): Promise { queue: state.queue.length, }, ) - if (isNewCommand(prompt.text)) { + if (prompt.mode !== "shell" && isNewCommand(prompt.text)) { drain() return } diff --git a/packages/opencode/src/cli/cmd/run/runtime.ts b/packages/opencode/src/cli/cmd/run/runtime.ts index 49620e01e8..f8a29316ec 100644 --- a/packages/opencode/src/cli/cmd/run/runtime.ts +++ b/packages/opencode/src/cli/cmd/run/runtime.ts @@ -51,6 +51,8 @@ type RunRuntimeInput = { files: RunInput["files"] initialInput?: string thinking: boolean + replay?: boolean + replayLimit?: number demo?: RunInput["demo"] } @@ -67,6 +69,8 @@ type RunLocalInput = { files: RunInput["files"] initialInput?: string thinking: boolean + replay?: boolean + replayLimit?: number demo?: RunInput["demo"] } @@ -490,6 +494,8 @@ async function runInteractiveRuntime(input: RunRuntimeInput): Promise { directory: ctx.directory, sessionID: state.sessionID, thinking: input.thinking, + replay: input.replay, + replayLimit: input.replayLimit, limits: () => state.limits, footer, trace: log, @@ -722,6 +728,8 @@ export async function runInteractiveLocalMode(input: RunLocalInput): Promise { if (session) { @@ -774,6 +782,8 @@ export async function runInteractiveMode(input: RunInput & { createSession?: Cre files: input.files, initialInput: input.initialInput, thinking: input.thinking, + replay: input.replay, + replayLimit: input.replayLimit, demo: input.demo, boot: async () => ({ sdk: input.sdk, diff --git a/packages/opencode/src/cli/cmd/run/session-data.ts b/packages/opencode/src/cli/cmd/run/session-data.ts index 2c3a33ec4c..b5cabb8c8f 100644 --- a/packages/opencode/src/cli/cmd/run/session-data.ts +++ b/packages/opencode/src/cli/cmd/run/session-data.ts @@ -61,13 +61,20 @@ type SessionCommit = StreamCommit // - text: part ID → full accumulated text so far // - sent: part ID → byte offset of last flushed text (for incremental output) // - end: part IDs whose time.end has arrived (part is finished) +// - shell: shell call ID → chosen transcript source for direct shell calls // - echo: message ID → bash outputs to strip from the next assistant chunk +type ShellCall = { + source: "shell" | "tool" + command?: string +} + export type SessionData = { includeUserText: boolean announced: boolean ids: Set tools: Set call: Map + shell: Map permissions: PermissionRequest[] questions: QuestionRequest[] role: Map @@ -104,6 +111,7 @@ export function createSessionData( ids: new Set(), tools: new Set(), call: new Map(), + shell: new Map(), permissions: [], questions: [], role: new Map(), @@ -621,6 +629,87 @@ function toolCommit( } } +function shellPartID(callID: string): string { + return `shell:${callID}` +} + +function claimShell(data: SessionData, callID: string, source: ShellCall["source"], command?: string): ShellCall { + const current = data.shell.get(callID) + if (current) { + if (command && !current.command) { + current.command = command + } + + return current + } + + const next = { + source, + ...(command ? { command } : {}), + } satisfies ShellCall + data.shell.set(callID, next) + return next +} + +function bashCommand(part: ToolPart): string | undefined { + if (part.tool !== "bash") { + return undefined + } + + const input = part.state.input + if (!input || typeof input !== "object" || Array.isArray(input)) { + return undefined + } + + const command = Reflect.get(input, "command") + return typeof command === "string" ? command : undefined +} + +function shellCommit( + input: { + callID: string + command: string + }, + next: Pick, +): SessionCommit { + return { + kind: "tool", + source: "tool", + partID: shellPartID(input.callID), + tool: "bash", + shell: input, + ...next, + } +} + +function startShell(callID: string, command: string): SessionCommit { + return shellCommit( + { + callID, + command, + }, + { + text: "running shell", + phase: "start", + toolState: "running", + }, + ) +} + +function doneShell(callID: string, command: string, output: string): SessionCommit { + return shellCommit( + { + callID, + command, + }, + { + text: output, + phase: "progress", + toolState: "completed", + }, + ) +} + function startTool(part: ToolPart): SessionCommit { return toolCommit(part, { text: toolStatus(part), @@ -681,6 +770,53 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { const data = input.data const event = input.event + if (event.type === "session.next.shell.started") { + if (event.properties.sessionID !== input.sessionID) { + return out(data, commits) + } + + const shell = claimShell(data, event.properties.callID, "shell", event.properties.command) + if (shell.source !== "shell") { + return out(data, commits) + } + + const partID = shellPartID(event.properties.callID) + if (data.ids.has(partID) || data.tools.has(partID)) { + return out(data, commits, patch({ status: "running shell" })) + } + + data.tools.add(partID) + commits.push(startShell(event.properties.callID, shell.command ?? event.properties.command)) + return out(data, commits, patch({ status: "running shell" })) + } + + if (event.type === "session.next.shell.ended") { + if (event.properties.sessionID !== input.sessionID) { + return out(data, commits) + } + + const shell = claimShell(data, event.properties.callID, "shell") + if (shell.source !== "shell") { + return out(data, commits) + } + + const partID = shellPartID(event.properties.callID) + const seen = data.tools.has(partID) + const command = shell.command ?? "" + data.tools.delete(partID) + if (data.ids.has(partID)) { + return out(data, commits) + } + + if (!seen && command) { + commits.push(startShell(event.properties.callID, command)) + } + + data.ids.add(partID) + commits.push(doneShell(event.properties.callID, command, event.properties.output)) + return out(data, commits) + } + if (event.type === "message.updated") { if (event.properties.sessionID !== input.sessionID) { return out(data, commits) @@ -782,6 +918,11 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { if (part.type === "tool") { const view = syncPermission(data, part) ?? syncQuestion(data, part) + if (part.tool === "bash" && part.callID) { + if (claimShell(data, part.callID, "tool", bashCommand(part)).source === "shell") { + return out(data, commits, view) + } + } if (part.state.status === "running") { if (data.ids.has(part.id)) { diff --git a/packages/opencode/src/cli/cmd/run/session-replay.ts b/packages/opencode/src/cli/cmd/run/session-replay.ts new file mode 100644 index 0000000000..3fafa366cd --- /dev/null +++ b/packages/opencode/src/cli/cmd/run/session-replay.ts @@ -0,0 +1,188 @@ +import type { Event, PermissionRequest, QuestionRequest } from "@kilocode/sdk/v2" +import { bootstrapSessionData, createSessionData, reduceSessionData, type SessionData } from "./session-data" +import { messagePrompt, type SessionMessages } from "./session.shared" +import type { FooterPatch, StreamCommit } from "./types" + +type ReplayInput = { + messages: SessionMessages + permissions: PermissionRequest[] + questions: QuestionRequest[] + thinking: boolean + limits: Record +} + +export type SessionReplay = { + data: SessionData + commits: StreamCommit[] + patch?: FooterPatch +} + +type ReplayMessage = { + commits: StreamCommit[] + patch?: FooterPatch +} + +function apply(data: SessionData, event: Event, sessionID: string, thinking: boolean, limits: Record) { + return reduceSessionData({ + data, + event, + sessionID, + thinking, + limits, + }) +} + +function mergePatch(left: FooterPatch | undefined, right: FooterPatch | undefined) { + if (!left) { + return right + } + + if (!right) { + return left + } + + return { + ...left, + ...right, + } +} + +function active(data: SessionData) { + return data.part.size > 0 || data.tools.size > 0 +} + +function replayPatch(data: SessionData, patch: FooterPatch | undefined) { + if (active(data)) { + if (!patch) { + return { + phase: "running", + } satisfies FooterPatch + } + + return { + ...patch, + phase: "running", + } satisfies FooterPatch + } + + if (data.permissions.length > 0 || data.questions.length > 0) { + if (!patch) { + return { + phase: "idle", + } satisfies FooterPatch + } + + return { + ...patch, + phase: "idle", + } satisfies FooterPatch + } + + if (!patch) { + return undefined + } + + return { + ...patch, + phase: "idle", + status: "", + } satisfies FooterPatch +} + +function replayMessage( + data: SessionData, + message: SessionMessages[number], + thinking: boolean, + limits: Record, +): ReplayMessage { + if (message.info.role === "user") { + const prompt = messagePrompt(message) + if (!prompt.text.trim()) { + return { + commits: [], + } + } + + return { + commits: [ + { + kind: "user", + text: prompt.text, + phase: "start", + source: "system", + messageID: message.info.id, + }, + ], + } + } + + const commits: StreamCommit[] = [] + let patch: FooterPatch | undefined + + const info = apply( + data, + { + id: `bootstrap:message:${message.info.id}`, + type: "message.updated", + properties: { + sessionID: message.info.sessionID, + info: message.info, + }, + }, + message.info.sessionID, + thinking, + limits, + ) + commits.push(...info.commits) + patch = mergePatch(patch, info.footer?.patch) + + for (const part of message.parts) { + const next = apply( + data, + { + id: `bootstrap:part:${part.id}`, + type: "message.part.updated", + properties: { + sessionID: part.sessionID, + part, + time: 0, + }, + }, + message.info.sessionID, + thinking, + limits, + ) + patch = mergePatch(patch, next.footer?.patch) + commits.push(...next.commits) + } + + return { + commits, + patch, + } +} + +export function replaySession(input: ReplayInput): SessionReplay { + const data = createSessionData() + const commits: StreamCommit[] = [] + let patch: FooterPatch | undefined + + bootstrapSessionData({ + data, + messages: input.messages, + permissions: input.permissions, + questions: input.questions, + }) + + for (const message of input.messages) { + const next = replayMessage(data, message, input.thinking, input.limits) + commits.push(...next.commits) + patch = mergePatch(patch, next.patch) + } + + return { + data, + commits, + patch: replayPatch(data, patch), + } +} diff --git a/packages/opencode/src/cli/cmd/run/session.shared.ts b/packages/opencode/src/cli/cmd/run/session.shared.ts index 14e69da2cc..7dbce26efd 100644 --- a/packages/opencode/src/cli/cmd/run/session.shared.ts +++ b/packages/opencode/src/cli/cmd/run/session.shared.ts @@ -60,7 +60,7 @@ function fileSource( } } -function prompt(msg: SessionMessages[number]): RunPrompt { +export function messagePrompt(msg: SessionMessages[number]): RunPrompt { const parts: RunPrompt["parts"] = [] let text = msg.parts .filter((part): part is Extract => { @@ -135,7 +135,7 @@ function turn(msg: SessionMessages[number]): Turn | undefined { } return { - prompt: prompt(msg), + prompt: messagePrompt(msg), provider: msg.info.model.providerID, model: msg.info.model.modelID, variant: msg.info.model.variant, diff --git a/packages/opencode/src/cli/cmd/run/stream.transport.ts b/packages/opencode/src/cli/cmd/run/stream.transport.ts index a94ebab522..ca053389c3 100644 --- a/packages/opencode/src/cli/cmd/run/stream.transport.ts +++ b/packages/opencode/src/cli/cmd/run/stream.transport.ts @@ -27,6 +27,7 @@ import { reduceSessionData, type SessionData, } from "./session-data" +import { replaySession } from "./session-replay" import { bootstrapSubagentCalls, bootstrapSubagentData, @@ -61,11 +62,15 @@ type Trace = { write(type: string, data?: unknown): void } +const StreamClosed = undefined as never + type StreamInput = { sdk: KiloClient directory?: string sessionID: string thinking: boolean + replay?: boolean + replayLimit?: number limits: () => Record footer: FooterApi trace?: Trace @@ -129,6 +134,8 @@ function sid(event: Event): string | undefined { } if ( + event.type === "session.next.shell.started" || + event.type === "session.next.shell.ended" || event.type === "permission.asked" || event.type === "permission.replied" || event.type === "question.asked" || @@ -413,12 +420,12 @@ function createLayer(input: StreamInput) { ), (events) => Effect.sync(() => { - void events.stream.return(undefined).catch(() => {}) + void events.stream.return(StreamClosed).catch(() => {}) }), ), ) closeStream = () => { - void events.stream.return(undefined).catch(() => {}) + void events.stream.return(StreamClosed).catch(() => {}) } input.trace?.write("recv.subscribe", { sessionID: input.sessionID, @@ -432,7 +439,12 @@ function createLayer(input: StreamInput) { blockerTick: 0, blockers: new Map(), } + let booting = true + const buffered: Event[] = [] + const replayedParts = new Set() const recovering = new Set() + const tracked = (sessionID: string | undefined) => + sessionID === input.sessionID || (!!sessionID && state.subagent.tabs.has(sessionID)) const currentSubagentState = () => { if (state.selectedSubagent && !state.subagent.tabs.has(state.selectedSubagent)) { state.selectedSubagent = undefined @@ -505,6 +517,27 @@ function createLayer(input: StreamInput) { state.footerView = current } + const resolveShellAgent = Effect.fn("RunStreamTransport.resolveShellAgent")(function* ( + agent: string | undefined, + ) { + if (agent) { + return agent + } + + const list = yield* Effect.promise(() => + input.sdk.app.agents(input.directory ? { directory: input.directory } : undefined, { throwOnError: true }), + ).pipe( + Effect.map((item) => item.data ?? []), + Effect.orElseSucceed(() => []), + ) + const next = list.find((item) => item.mode !== "subagent" && item.hidden !== true)?.name + if (next) { + return next + } + + return yield* Effect.fail(new Error("no primary agent available for shell mode")) + }) + const recoverQuestion = Effect.fn("RunStreamTransport.recoverQuestion")(function* (partID: string) { if (recovering.has(partID)) { return @@ -550,11 +583,11 @@ function createLayer(input: StreamInput) { } }) - const messages = (sessionID: string, limit: number) => + const messages = (sessionID: string, limit?: number) => Effect.promise(() => input.sdk.session.messages({ sessionID, - limit, + ...(typeof limit === "number" ? { limit } : {}), }), ).pipe( Effect.map((item) => item.data ?? []), @@ -596,7 +629,14 @@ function createLayer(input: StreamInput) { const bootstrap = Effect.fn("RunStreamTransport.bootstrap")(function* () { const [messagesList, children, permissions, questions] = yield* Effect.all( [ - messages(input.sessionID, SUBAGENT_BOOTSTRAP_LIMIT), + messages( + input.sessionID, + input.replay + ? input.replayLimit === undefined + ? undefined + : Math.max(input.replayLimit, SUBAGENT_BOOTSTRAP_LIMIT) + : SUBAGENT_BOOTSTRAP_LIMIT, + ), Effect.promise(() => input.sdk.session.children({ sessionID: input.sessionID, @@ -619,12 +659,52 @@ function createLayer(input: StreamInput) { }, ) - bootstrapSessionData({ - data: state.data, - messages: messagesList, - permissions: permissions.filter((item) => item.sessionID === input.sessionID), - questions: questions.filter((item) => item.sessionID === input.sessionID), - }) + const sessionPermissions = permissions.filter((item) => item.sessionID === input.sessionID) + const sessionQuestions = questions.filter((item) => item.sessionID === input.sessionID) + const history = input.replay + ? replaySession({ + messages: messagesList, + permissions: sessionPermissions, + questions: sessionQuestions, + thinking: input.thinking, + limits: input.limits(), + }) + : undefined + const replay = + history && input.replayLimit !== undefined && messagesList.length > input.replayLimit + ? replaySession({ + messages: messagesList.slice(-input.replayLimit), + permissions: sessionPermissions, + questions: sessionQuestions, + thinking: input.thinking, + limits: input.limits(), + }) + : history + + replayedParts.clear() + if (history) { + state.data = history.data + } + + if (!history) { + bootstrapSessionData({ + data: state.data, + messages: messagesList, + permissions: sessionPermissions, + questions: sessionQuestions, + }) + } + + if (replay) { + for (const [partID] of replay.data.text) { + if (!replay.data.part.has(partID)) { + continue + } + + replayedParts.add(partID) + } + } + bootstrapSubagentData({ data: state.subagent, messages: messagesList, @@ -632,6 +712,7 @@ function createLayer(input: StreamInput) { permissions, questions, }) + clearFinishedSubagents(state.subagent) for (const request of [ ...state.data.permissions, @@ -642,9 +723,29 @@ function createLayer(input: StreamInput) { seedBlocker(request.id) } + if (replay) { + const activeCommitIDs = new Set([...state.data.part.keys(), ...state.data.tools]) + for (const commit of replay.commits) { + input.trace?.write("ui.commit", commit) + input.footer.append(commit) + + if (commit.partID && activeCommitIDs.has(commit.partID)) { + continue + } + + yield* Effect.promise(() => input.footer.idle()).pipe(Effect.orElseSucceed(() => undefined)) + } + } + const snapshot = currentSubagentState() traceTabs(input.trace, [], snapshot.tabs) - syncFooter([], undefined, snapshot) + syncFooter([], replay?.patch, snapshot) + if (replay) { + yield* Effect.promise(() => input.footer.idle()).pipe(Effect.orElseSucceed(() => undefined)) + } + + booting = false + yield* drainBuffered() const sessions = [...state.subagent.tabs.keys()] if (sessions.length === 0) { @@ -738,6 +839,86 @@ function createLayer(input: StreamInput) { }) } + const applyEvent = Effect.fn("RunStreamTransport.applyEvent")(function* (event: Event) { + if (event.type === "message.part.delta" && event.properties.sessionID === input.sessionID) { + if (replayedParts.has(event.properties.partID)) { + const seen = state.data.text.get(event.properties.partID) ?? "" + if (seen.endsWith(event.properties.delta)) { + return + } + + replayedParts.delete(event.properties.partID) + } + } + + trackBlocker(event) + + const prev = event.type === "message.part.updated" ? listSubagentTabs(state.subagent) : undefined + const next = reduceSessionData({ + data: state.data, + event, + sessionID: input.sessionID, + thinking: input.thinking, + limits: input.limits(), + }) + state.data = next.data + + if ( + event.type === "message.part.updated" && + event.properties.part.sessionID === input.sessionID && + event.properties.part.type === "tool" && + event.properties.part.tool === "question" && + event.properties.part.state.status === "running" && + state.data.questions.length === 0 + ) { + yield* recoverQuestion(event.properties.part.id).pipe( + Effect.forkIn(scope, { startImmediately: true }), + Effect.asVoid, + ) + } + + const changed = reduceSubagentData({ + data: state.subagent, + event, + sessionID: input.sessionID, + thinking: input.thinking, + limits: input.limits(), + }) + if (changed && prev) { + traceTabs(input.trace, prev, listSubagentTabs(state.subagent)) + } + releaseBlocker(event) + + syncFooter(next.commits, next.footer?.patch, changed ? currentSubagentState() : undefined) + + touch(event) + yield* mark(event) + }) + + const drainBuffered = Effect.fn("RunStreamTransport.drainBuffered")(function* () { + let pending = buffered.splice(0) + while (pending.length > 0) { + const next: Event[] = [] + let changed = false + for (const event of pending) { + if (!tracked(sid(event))) { + next.push(event) + continue + } + + changed = true + yield* applyEvent(event) + } + + if (!changed) { + buffered.push(...next) + return + } + + pending = next + } + }) + const watch = Effect.fn("RunStreamTransport.watch")(() => Stream.fromAsyncIterable(events.stream, (error) => error instanceof Error ? error : new Error(String(error)), @@ -762,53 +943,25 @@ function createLayer(input: StreamInput) { } const sessionID = sid(event) - if (sessionID !== input.sessionID && (!sessionID || !state.subagent.tabs.has(sessionID))) { + if (booting) { + if (sessionID) { + input.trace?.write("recv.event", event) + buffered.push(event) + } + return + } + + if (!tracked(sessionID)) { + if (sessionID) { + input.trace?.write("recv.event", event) + buffered.push(event) + } return } input.trace?.write("recv.event", event) - trackBlocker(event) - - const prev = event.type === "message.part.updated" ? listSubagentTabs(state.subagent) : undefined - const next = reduceSessionData({ - data: state.data, - event, - sessionID: input.sessionID, - thinking: input.thinking, - limits: input.limits(), - }) - state.data = next.data - - if ( - event.type === "message.part.updated" && - event.properties.part.sessionID === input.sessionID && - event.properties.part.type === "tool" && - event.properties.part.tool === "question" && - event.properties.part.state.status === "running" && - state.data.questions.length === 0 - ) { - yield* recoverQuestion(event.properties.part.id).pipe( - Effect.forkIn(scope, { startImmediately: true }), - Effect.asVoid, - ) - } - - const changed = reduceSubagentData({ - data: state.subagent, - event, - sessionID: input.sessionID, - thinking: input.thinking, - limits: input.limits(), - }) - if (changed && prev) { - traceTabs(input.trace, prev, listSubagentTabs(state.subagent)) - } - releaseBlocker(event) - - syncFooter(next.commits, next.footer?.patch, changed ? currentSubagentState() : undefined) - - touch(event) - yield* mark(event) + yield* applyEvent(event) + yield* drainBuffered() }), ), Effect.catch((error) => (abort.signal.aborted ? Effect.void : fail(error))), @@ -823,8 +976,8 @@ function createLayer(input: StreamInput) { ), ) - yield* bootstrap() yield* Scope.provide(scope)(watch().pipe(Effect.forkScoped)) + yield* bootstrap() const runPromptTurn = Effect.fn("RunStreamTransport.runPromptTurn")(function* (next: SessionTurnInput) { if (closed || next.signal?.aborted || input.footer.isClosed) { @@ -877,66 +1030,108 @@ function createLayer(input: StreamInput) { ], } const command = next.prompt.command - const send = command - ? Effect.sync(() => { - input.trace?.write("send.command", { sessionID: input.sessionID, command: command.name }) - }).pipe( - Effect.andThen( - Effect.promise(() => - input.sdk.session.command( - { - sessionID: input.sessionID, - agent: next.agent, - model: next.model ? `${next.model.providerID}/${next.model.modelID}` : undefined, - variant: next.variant, - command: command.name, - arguments: command.arguments, - parts: [ - ...(next.includeFiles ? next.files : []), - ...next.prompt.parts.filter( - (item): item is Extract => item.type === "file", + const send = + next.prompt.mode === "shell" + ? Effect.sync(() => { + input.trace?.write("send.shell", { + sessionID: input.sessionID, + command: next.prompt.text, + }) + }).pipe( + Effect.andThen( + resolveShellAgent(next.agent) + .pipe( + Effect.flatMap((agent) => + Effect.promise(() => + input.sdk.session.shell( + { + sessionID: input.sessionID, + agent, + model: next.model, + command: next.prompt.text, + }, + { signal: turn.signal, throwOnError: true }, + ), ), - ], - }, - { signal: turn.signal }, + ), + ) + .pipe( + Effect.tap(() => + Effect.sync(() => { + input.trace?.write("send.shell.ok", { + sessionID: input.sessionID, + }) + item.armed = true + item.live = true + }), + ), + Effect.flatMap(() => Deferred.succeed(item.done, undefined).pipe(Effect.ignore)), + Effect.catch((error) => Deferred.fail(item.done, error).pipe(Effect.ignore)), + Effect.forkIn(scope, { startImmediately: true }), + Effect.asVoid, + ), + ), + ) + : command + ? Effect.sync(() => { + input.trace?.write("send.command", { sessionID: input.sessionID, command: command.name }) + }).pipe( + Effect.andThen( + Effect.promise(() => + input.sdk.session.command( + { + sessionID: input.sessionID, + agent: next.agent, + model: next.model ? `${next.model.providerID}/${next.model.modelID}` : undefined, + variant: next.variant, + command: command.name, + arguments: command.arguments, + parts: [ + ...(next.includeFiles ? next.files : []), + ...next.prompt.parts.filter( + (item): item is Extract => item.type === "file", + ), + ], + }, + { signal: turn.signal }, + ), + ).pipe( + Effect.tap(() => + Effect.sync(() => { + input.trace?.write("send.command.ok", { + sessionID: input.sessionID, + command: command.name, + }) + item.armed = true + item.live = true + }), + ), + Effect.flatMap(() => Deferred.succeed(item.done, undefined).pipe(Effect.ignore)), + Effect.catch((error) => Deferred.fail(item.done, error).pipe(Effect.ignore)), + Effect.forkIn(scope, { startImmediately: true }), + Effect.asVoid, + ), + ), + ) + : Effect.sync(() => { + input.trace?.write("send.prompt", req) + }).pipe( + Effect.andThen( + Effect.promise(() => + input.sdk.session.promptAsync(req, { + signal: turn.signal, + }), + ), ), - ).pipe( Effect.tap(() => Effect.sync(() => { - input.trace?.write("send.command.ok", { + input.trace?.write("send.prompt.ok", { sessionID: input.sessionID, - command: command.name, }) item.armed = true - item.live = true }), ), - Effect.flatMap(() => Deferred.succeed(item.done, undefined).pipe(Effect.ignore)), - Effect.catch((error) => Deferred.fail(item.done, error).pipe(Effect.ignore)), - Effect.forkIn(scope, { startImmediately: true }), - Effect.asVoid, - ), - ), - ) - : Effect.sync(() => { - input.trace?.write("send.prompt", req) - }).pipe( - Effect.andThen( - Effect.promise(() => - input.sdk.session.promptAsync(req, { - signal: turn.signal, - }), - ), - ), - Effect.tap(() => - Effect.sync(() => { - input.trace?.write("send.prompt.ok", { - sessionID: input.sessionID, - }) - item.armed = true - }), - ), - ) + ) yield* send.pipe( Effect.flatMap(() => { diff --git a/packages/opencode/src/cli/cmd/run/subagent-data.ts b/packages/opencode/src/cli/cmd/run/subagent-data.ts index 31b8604294..3e7d1ccaa1 100644 --- a/packages/opencode/src/cli/cmd/run/subagent-data.ts +++ b/packages/opencode/src/cli/cmd/run/subagent-data.ts @@ -420,9 +420,26 @@ function ensureBlockerTab( title: string | undefined, kind: "permission" | "question", ) { - if (data.tabs.has(sessionID)) { + const current = data.tabs.get(sessionID) + if (current) { ensureDetail(data, sessionID) - return false + if (current.status !== "running") { + return false + } + + const next = { + ...current, + description: kind === "permission" ? "Pending permission" : "Pending question", + status: "running" as const, + title: current.title ?? title, + lastUpdatedAt: Date.now(), + } + if (sameSubagentTab(current, next)) { + return false + } + + data.tabs.set(sessionID, next) + return true } data.tabs.set(sessionID, { diff --git a/packages/opencode/src/cli/cmd/run/tool.ts b/packages/opencode/src/cli/cmd/run/tool.ts index e9247cf694..58ac575438 100644 --- a/packages/opencode/src/cli/cmd/run/tool.ts +++ b/packages/opencode/src/cli/cmd/run/tool.ts @@ -35,7 +35,7 @@ import { webSearchProviderLabel, type WebSearchTool } from "@/tool/websearch" import type { WriteTool } from "@/tool/write" import { LANGUAGE_EXTENSIONS } from "@/lsp/language" import * as Locale from "@/util/locale" -import type { RunDiffStyle, RunEntryBody, StreamCommit, ToolSnapshot } from "./types" +import type { RunEntryBody, StreamCommit, ToolSnapshot } from "./types" export type ToolView = { output: boolean @@ -626,6 +626,10 @@ function scrollBashStart(p: ToolProps): string { const desc = p.input.description || "Shell" const wd = p.input.workdir ?? "" const dir = wd && wd !== "." ? toolPath(wd) : "" + if (cmd && desc === "Shell" && !dir) { + return `$ ${cmd}` + } + const title = dir && !desc.includes(dir) ? `${desc} in ${dir}` : desc if (!cmd) { @@ -1248,7 +1252,7 @@ function frame(part: ToolPart): ToolFrame { raw: "", name: part.tool, input: dict(state.input), - meta: dict(state.metadata), + meta: "metadata" in part.state ? dict(part.state.metadata) : {}, state, status: text(state.status), error: text(state.error), @@ -1261,7 +1265,7 @@ export function toolFrame(commit: StreamCommit, raw: string): ToolFrame { raw, name: commit.tool || commit.part?.tool || "tool", input: dict(state.input), - meta: dict(state.metadata), + meta: commit.part?.state && "metadata" in commit.part.state ? dict(commit.part.state.metadata) : {}, state, status: commit.toolState ?? text(state.status), error: (commit.toolError ?? "").trim(), @@ -1403,7 +1407,32 @@ function structuredBody(commit: StreamCommit, raw: string): RunEntryBody | undef } } +function shellOutput(command: string, raw: string): string | undefined { + const body = stripAnsi(raw).replace(/^\n+/, "").replace(/\n+$/, "") + if (!body) { + return undefined + } + + if (!command) { + return body + } + + return `\n${body}` +} + export function toolEntryBody(commit: StreamCommit, raw: string): RunEntryBody | undefined { + if (commit.shell) { + if (commit.phase === "start") { + return textBody(`$ ${commit.shell.command}`) + } + + if (commit.phase === "progress") { + return textBody(shellOutput(commit.shell.command, raw) ?? "") + } + + return undefined + } + const ctx = toolFrame(commit, raw) const view = toolView(ctx.name) diff --git a/packages/opencode/src/cli/cmd/run/types.ts b/packages/opencode/src/cli/cmd/run/types.ts index e6709d6dcd..d1d641bfb4 100644 --- a/packages/opencode/src/cli/cmd/run/types.ts +++ b/packages/opencode/src/cli/cmd/run/types.ts @@ -34,6 +34,7 @@ export type RunProvider = NonNullable - - - - - - - - - - - + + + + + + + + + @@ -267,7 +272,6 @@ function App(props: { onSnapshot?: () => Promise }) { const dialog = useDialog() const local = useLocal() const kv = useKV() - const command = useCommandPalette() const keymap = useOpencodeKeymap() const event = useEvent() const sdk = useSDK() @@ -275,6 +279,7 @@ function App(props: { onSnapshot?: () => Promise }) { const themeState = useTheme() const { theme, mode, setMode, locked, lock, unlock } = themeState const sync = useSync() + const project = useProject() const exit = useExit() const promptRef = usePromptRef() const routes: RouteMap = new Map() @@ -443,15 +448,22 @@ function App(props: { onSnapshot?: () => Promise }) { ) const connected = useConnected() + const currentWorktreeWorkspace = createMemo(() => { + const workspaceID = project.workspace.current() + if (!workspaceID) return + const workspace = project.workspace.get(workspaceID) + if (workspace?.type !== "worktree" || !workspace.directory) return + return workspace + }) const appCommands = createMemo(() => [ { - name: "command.palette.show", + name: COMMAND_PALETTE_COMMAND, title: "Show command palette", category: "System", hidden: true, run: () => { - command.show() + dialog.replace(() => ) }, }, { @@ -479,6 +491,20 @@ function App(props: { onSnapshot?: () => Promise }) { dialog.clear() }, }, + { + name: "workspace.copy_path", + title: "Copy worktree path", + category: "Workspace", + enabled: () => currentWorktreeWorkspace() !== undefined, + run: async () => { + const workspace = currentWorktreeWorkspace() + if (!workspace?.directory) return + await Clipboard.copy(workspace.directory) + .then(() => toast.show({ message: "Copied worktree path", variant: "info" })) + .catch(toast.error) + dialog.clear() + }, + }, ...Array.from({ length: 9 }, (_, i) => ({ name: `session.quick_switch.${i + 1}`, title: `Switch to session in quick slot ${i + 1}`, @@ -801,14 +827,13 @@ function App(props: { onSnapshot?: () => Promise }) { })) useBindings(() => ({ - enabled: command.matcher, + mode: KILO_BASE_MODE, bindings: tuiConfig.keybinds.gather("app", appBindingCommands), })) useBindings(() => ({ + mode: KILO_BASE_MODE, enabled: () => { - const ok = command.matcher.get() - if (!ok) return false const current = promptRef.current if (!current?.focused) return true return current.current.input === "" @@ -817,7 +842,7 @@ function App(props: { onSnapshot?: () => Promise }) { })) event.on(TuiEvent.CommandExecute.type, (evt) => { - command.run(evt.properties.command) + keymap.dispatchCommand(evt.properties.command) }) event.on(TuiEvent.ToastShow.type, (evt) => { diff --git a/packages/opencode/src/cli/cmd/tui/component/command-palette.tsx b/packages/opencode/src/cli/cmd/tui/component/command-palette.tsx new file mode 100644 index 0000000000..0d6deeedcd --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/command-palette.tsx @@ -0,0 +1,79 @@ +import { createMemo } from "solid-js" +import { DialogSelect, type DialogSelectRef } from "@tui/ui/dialog-select" +import { type DialogContext } from "@tui/ui/dialog" +import { + COMMAND_PALETTE_COMMAND, + formatKeyBindings, + type OpenTuiKeymap, + useKeymapSelector, + useOpencodeKeymap, +} from "../keymap" +import { useTuiConfig } from "../context/tui-config" + +type PaletteCommandEntry = ReturnType[number] + +function isVisiblePaletteCommand(command: PaletteCommandEntry["command"]) { + return command.hidden !== true && command.name !== COMMAND_PALETTE_COMMAND +} + +function isSuggestedPaletteCommand(entry: PaletteCommandEntry) { + const suggested = entry.command.suggested + if (typeof suggested === "boolean") return suggested + if (typeof suggested === "function") return suggested() === true + return false +} + +export function CommandPaletteDialog() { + const config = useTuiConfig() + const keymap = useOpencodeKeymap() + const entries = useKeymapSelector((keymap: OpenTuiKeymap) => { + const query = { + namespace: "palette", + } + const reachable = keymap.getCommandEntries({ + ...query, + visibility: "reachable", + filter: isVisiblePaletteCommand, + }) + const registeredBindings = keymap.getCommandBindings({ + visibility: "registered", + commands: reachable.map((entry) => entry.command.name), + }) + + return reachable.map((entry) => ({ + ...entry, + bindings: registeredBindings.get(entry.command.name) ?? entry.bindings, + })) + }) + const options = createMemo(() => + entries().map((entry) => ({ + title: typeof entry.command.title === "string" ? entry.command.title : entry.command.name, + description: typeof entry.command.desc === "string" ? entry.command.desc : undefined, + category: typeof entry.command.category === "string" ? entry.command.category : undefined, + footer: formatKeyBindings(entry.bindings, config), + value: entry.command.name, + suggested: isSuggestedPaletteCommand(entry), + onSelect: (dialog: DialogContext) => { + dialog.clear() + keymap.dispatchCommand(entry.command.name) + }, + })), + ) + + let ref: DialogSelectRef + const list = () => { + if (ref?.filter) return options() + return [ + ...options() + .filter((option) => option.suggested) + .map((option) => ({ + ...option, + value: `suggested:${option.value}`, + category: "Suggested", + })), + ...options(), + ] + } + + return (ref = value)} title="Commands" options={list()} /> +} diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx index 6d6c62450e..1d58401ebc 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-tag.tsx @@ -1,12 +1,14 @@ import { createMemo, createResource } from "solid-js" import { DialogSelect } from "@tui/ui/dialog-select" import { useDialog } from "@tui/ui/dialog" +import { useProject } from "@tui/context/project" import { useSDK } from "@tui/context/sdk" import { createStore } from "solid-js/store" export function DialogTag(props: { onSelect?: (value: string) => void }) { const sdk = useSDK() const dialog = useDialog() + const project = useProject() const [store] = createStore({ filter: "", @@ -17,6 +19,7 @@ export function DialogTag(props: { onSelect?: (value: string) => void }) { async () => { const result = await sdk.client.find.files({ query: store.filter, + workspace: project.workspace.current(), }) if (result.error) return [] const sliced = (result.data ?? []).slice(0, 5) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-create.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-create.tsx index a3c38e9109..542e6fd9d4 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-create.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-workspace-create.tsx @@ -108,7 +108,7 @@ export async function warpWorkspaceSession(input: { }) .catch(() => undefined) if (!result?.data) { - if (result?.error?.name === "VcsApplyError") { + if (result?.error && "name" in result.error && result.error.name === "VcsApplyError") { await DialogAlert.show( input.dialog, "Unable to Warp Session", diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 3f7604653c..2bda73cff7 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -6,20 +6,20 @@ import { firstBy } from "remeda" import { createMemo, createResource, createEffect, onMount, onCleanup, Index, Show, createSignal } from "solid-js" import { createStore } from "solid-js/store" import { useEditorContext } from "@tui/context/editor" +import { useProject } from "@tui/context/project" import { useSDK } from "@tui/context/sdk" import { useSync } from "@tui/context/sync" import { getScrollAcceleration } from "../../util/scroll" import { useTuiConfig } from "../../context/tui-config" import { useTheme, selectedForeground } from "@tui/context/theme" import { SplitBorder } from "@tui/component/border" -import { useCommandPalette } from "../../context/command-palette" import { useTerminalDimensions } from "@opentui/solid" import { Locale } from "@/util/locale" import type { PromptInfo } from "./history" import { useFrecency } from "./frecency" -import { useBindings } from "../../keymap" +import { useBindings, useCommandSlashes, useOpencodeModeStack } from "../../keymap" import { Reference } from "@/reference/reference" -import type { Config } from "@/config/config" +import { ConfigReference } from "@/config/reference" import { displayCharAt, mentionTriggerIndex } from "@/cli/cmd/prompt-display" function removeLineRange(input: string) { @@ -85,7 +85,9 @@ export function Autocomplete(props: { const editor = useEditorContext() const sdk = useSDK() const sync = useSync() - const command = useCommandPalette() + const project = useProject() + const slashes = useCommandSlashes() + const modeStack = useOpencodeModeStack() const { theme } = useTheme() const dimensions = useTerminalDimensions() const frecency = useFrecency() @@ -99,6 +101,12 @@ export function Autocomplete(props: { const [positionTick, setPositionTick] = createSignal(0) + createEffect(() => { + if (!store.visible) return + const popMode = modeStack.push("autocomplete") + onCleanup(popMode) + }) + createEffect(() => { if (store.visible) { let lastPos = { x: 0, y: 0, width: 0 } @@ -310,7 +318,7 @@ export function Autocomplete(props: { `Referenced configured reference @${reference.name}.`, ...(reference.kind === "local" ? ["Kind: local directory"] : []), ...(reference.kind === "git" ? ["Kind: git repository"] : []), - ...(reference.kind === "invalid" ? [`Repository: ${reference.repository}`] : []), + ...(reference.kind === "invalid" && reference.repository ? [`Repository: ${reference.repository}`] : []), ...(reference.kind === "git" ? [`Repository: ${reference.repository}`] : []), ...(reference.kind === "git" && reference.branch ? [`Branch/ref: ${reference.branch}`] : []), ...(reference.kind === "invalid" ? [] : [`Reference root: ${reference.path}`]), @@ -324,7 +332,7 @@ export function Autocomplete(props: { const references = createMemo(() => Reference.resolveAll({ - references: (sync.data.config.reference ?? {}) as NonNullable, + references: ConfigReference.normalize(sync.data.config.reference ?? {}), directory: sync.path.directory || process.cwd(), worktree: sync.path.worktree || sync.path.directory || process.cwd(), }), @@ -365,7 +373,6 @@ export function Autocomplete(props: { const { filename, part } = createFilePart(item, lineRange) const index = store.visible === "@" ? store.index : props.input().cursorOffset - command.suspend(false) setStore("visible", false) setStore("index", index) insertPart(filename, part) @@ -382,6 +389,7 @@ export function Autocomplete(props: { // Get files from SDK const result = await sdk.client.find.files({ query: baseQuery, + workspace: project.workspace.current(), }) const options: AutocompleteOption[] = [] @@ -536,7 +544,7 @@ export function Autocomplete(props: { ) const commands = createMemo((): AutocompleteOption[] => { - const results: AutocompleteOption[] = [...command.slashes()] + const results: AutocompleteOption[] = [...slashes()] for (const serverCommand of sync.data.command) { if (serverCommand.source === "skill") continue @@ -727,7 +735,6 @@ export function Autocomplete(props: { })) function show(mode: "@" | "/") { - command.suspend(true) setStore({ visible: mode, index: props.input().cursorOffset, @@ -744,7 +751,6 @@ export function Autocomplete(props: { draft.input = props.input().plainText }) } - command.suspend(false) setStore("visible", false) } diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 9abecccc4d..a8e0d9f4fe 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -28,7 +28,7 @@ import { MessageID, PartID } from "@/session/schema" import { createStore, produce, unwrap } from "solid-js/store" import { usePromptHistory, type PromptInfo } from "./history" import { computePromptTraits } from "./traits" -import { assign } from "./part" +import { assign, expandPastedTextPlaceholders } from "./part" import { usePromptStash } from "./stash" import { DialogStash } from "../dialog-stash" import { type AutocompleteRef, Autocomplete } from "./autocomplete" @@ -59,13 +59,11 @@ import { DialogWorkspaceUnavailable } from "../dialog-workspace-unavailable" import { useArgs } from "@tui/context/args" import { Flag } from "@opencode-ai/core/flag/flag" import { type WorkspaceStatus } from "../workspace-label" -import { useCommandPalette } from "../../context/command-palette" -import { useBindings, useCommandShortcut, useLeaderActive, useOpencodeKeymap } from "../../keymap" +import { KILO_BASE_MODE, useBindings, useCommandShortcut, useLeaderActive, useOpencodeKeymap } from "../../keymap" import { useTuiConfig } from "../../context/tui-config" export type PromptProps = { sessionID?: string - workspaceID?: string visible?: boolean disabled?: boolean onSubmit?: () => void @@ -152,7 +150,6 @@ export function Prompt(props: PromptProps) { const status = createMemo(() => sync.data.session_status?.[props.sessionID ?? ""] ?? { type: "idle" }) const history = usePromptHistory() const stash = usePromptStash() - const command = useCommandPalette() const keymap = useOpencodeKeymap() const agentShortcut = useCommandShortcut("agent.cycle") const paletteShortcut = useCommandShortcut("command.palette.show") @@ -203,7 +200,6 @@ export function Prompt(props: PromptProps) { const [cursorVersion, setCursorVersion] = createSignal(0) const currentProviderLabel = createMemo(() => local.model.parsed().provider) const hasRightContent = createMemo(() => Boolean(props.right)) - const defaultWorkspaceID = createMemo(() => props.workspaceID ?? project.workspace.current()) function selectWorkspace(selection: WorkspaceSelection | undefined) { setWorkspaceSelection(selection) @@ -629,7 +625,7 @@ export function Prompt(props: PromptProps) { })) useBindings(() => ({ - enabled: command.matcher, + mode: KILO_BASE_MODE, bindings: tuiConfig.keybinds.gather("prompt.palette", [ "prompt.submit", "prompt.editor", @@ -1063,7 +1059,7 @@ export function Prompt(props: PromptProps) { if (sessionID == null) { const workspace = workspaceSelection() const workspaceID = iife(() => { - if (!workspace) return defaultWorkspaceID() + if (!workspace) return undefined if (workspace.type === "none") return undefined if (workspace.type === "existing") return workspace.workspaceID return undefined @@ -1424,17 +1420,7 @@ export function Prompt(props: PromptProps) { | undefined >(() => { const selected = workspaceSelection() - if (!selected) { - const workspaceID = defaultWorkspaceID() - if (props.sessionID || !workspaceID) return - const workspace = project.workspace.get(workspaceID) - return { - type: "existing", - workspaceType: workspace?.type ?? "unknown", - workspaceName: workspace?.name ?? workspaceID, - status: project.workspace.status(workspaceID) ?? "error", - } - } + if (!selected) return if (selected.type === "none") return if (props.sessionID && !workspaceCreating()) return if (selected.type === "new") { @@ -1452,7 +1438,10 @@ export function Prompt(props: PromptProps) { }) const spinnerDef = createMemo(() => { - const agent = local.agent.current() + const agent = + status().type !== "idle" + ? (local.agent.list().find((a) => a.name === lastUserMessage()?.agent) ?? local.agent.current()) + : local.agent.current() const color = agent ? local.agent.color(agent.name) : theme.border return { frames: createFrames({ @@ -1544,6 +1533,9 @@ export function Prompt(props: PromptProps) { }} ref={(r: TextareaRenderable) => { input = r + Object.assign(r, { + getClipboardText: (text: string) => expandPastedTextPlaceholders(text, store.prompt.parts), + }) setInputTarget(r) if (promptPartTypeId === 0) { promptPartTypeId = input.extmarks.registerType("prompt-part") diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/part.ts b/packages/opencode/src/cli/cmd/tui/component/prompt/part.ts index 8cdcef6067..c5ab85bc1e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/part.ts +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/part.ts @@ -14,3 +14,10 @@ export function assign(part: Item): Item & { id: PartID } { id: PartID.ascending(), } } + +export function expandPastedTextPlaceholders(text: string, parts: PromptInfo["parts"]) { + return parts.reduce((result, part) => { + if (part.type !== "text" || !part.source?.text) return result + return result.replace(part.source.text.value, part.text) + }, text) +} diff --git a/packages/opencode/src/cli/cmd/tui/config/keybind.ts b/packages/opencode/src/cli/cmd/tui/config/keybind.ts index bd26cd5d95..c03123aed1 100644 --- a/packages/opencode/src/cli/cmd/tui/config/keybind.ts +++ b/packages/opencode/src/cli/cmd/tui/config/keybind.ts @@ -59,6 +59,19 @@ export const Definitions = { command_list: keybind("ctrl+p", "List available commands"), help_show: keybind("none", "Open help dialog"), docs_open: keybind("none", "Open documentation"), + diff_close: keybind("escape,q", "Close diff viewer"), + diff_toggle: keybind("enter,space", "Toggle diff viewer item"), + diff_expand: keybind("right", "Expand diff viewer item"), + diff_expand_all: keybind("E", "Expand all diff viewer folders"), + diff_collapse: keybind("left", "Collapse diff viewer item"), + diff_switch_focus: keybind("tab", "Switch diff viewer focus"), + diff_next_file: keybind("n", "Jump to next diff file"), + diff_previous_file: keybind("p", "Jump to previous diff file"), + diff_toggle_file_tree: keybind("b", "Toggle diff viewer file tree"), + diff_single_patch: keybind("s", "Toggle single patch view"), + diff_switch_source: keybind("d", "Switch diff viewer source"), + diff_toggle_view: keybind("v", "Toggle diff viewer split or unified view"), + diff_help: keybind("?", "Show more diff viewer shortcuts"), editor_open: keybind("e", "Open external editor"), theme_list: keybind("t", "List available themes"), @@ -188,6 +201,7 @@ export const Definitions = { "dialog.select.home": keybind("home", "Move to first dialog item"), "dialog.select.end": keybind("end", "Move to last dialog item"), "dialog.select.submit": keybind("return", "Submit selected dialog item"), + "dialog.prompt.submit": keybind("return", "Submit dialog prompt"), "dialog.mcp.toggle": keybind("space", "Toggle MCP in MCP dialog"), "prompt.autocomplete.prev": keybind("up,ctrl+p", "Move to previous autocomplete item"), "prompt.autocomplete.next": keybind("down,ctrl+n", "Move to next autocomplete item"), @@ -244,6 +258,19 @@ export const CommandMap = { command_list: "command.palette.show", help_show: "help.show", docs_open: "docs.open", + diff_close: "diff.close", + diff_toggle: "diff.toggle", + diff_expand: "diff.expand", + diff_expand_all: "diff.expand_all", + diff_collapse: "diff.collapse", + diff_switch_focus: "diff.switch_focus", + diff_next_file: "diff.next_file", + diff_previous_file: "diff.previous_file", + diff_toggle_file_tree: "diff.toggle_file_tree", + diff_single_patch: "diff.single_patch", + diff_switch_source: "diff.switch_source", + diff_toggle_view: "diff.toggle_view", + diff_help: "diff.help", editor_open: "prompt.editor", theme_list: "theme.switch", theme_switch_mode: "theme.switch_mode", diff --git a/packages/opencode/src/cli/cmd/tui/context/command-palette.tsx b/packages/opencode/src/cli/cmd/tui/context/command-palette.tsx deleted file mode 100644 index 07cca99074..0000000000 --- a/packages/opencode/src/cli/cmd/tui/context/command-palette.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { createContext, createMemo, createSignal, useContext, type Accessor, type ParentProps } from "solid-js" -import { DialogSelect, type DialogSelectRef } from "@tui/ui/dialog-select" -import { useDialog, type DialogContext } from "@tui/ui/dialog" -import { - formatKeyBindings, - reactiveMatcherFromSignal, - type OpenTuiKeymap, - useKeymapSelector, - useOpencodeKeymap, -} from "../keymap" -import { useTuiConfig } from "./tui-config" - -type SlashEntry = { - display: string - description?: string - aliases?: string[] - onSelect: () => void -} - -type CommandPaletteContext = { - run(command: string): void - show(): void - slashes: Accessor - suspend(enabled: boolean): void - readonly suspended: boolean - matcher: ReturnType -} - -const COMMAND_PALETTE_DIALOG = "command.palette.show" -const ctx = createContext() -type PaletteCommandEntry = ReturnType[number] - -function isVisiblePaletteCommand(entry: PaletteCommandEntry) { - return entry.command.hidden !== true && entry.command.name !== COMMAND_PALETTE_DIALOG -} - -function isSuggestedPaletteCommand(entry: PaletteCommandEntry) { - const suggested = entry.command.suggested - if (typeof suggested === "boolean") return suggested - if (typeof suggested === "function") return suggested() === true - return false -} - -export function CommandPaletteProvider(props: ParentProps) { - const dialog = useDialog() - const keymap = useOpencodeKeymap() - const [suspendCount, setSuspendCount] = createSignal(0) - const entries = useKeymapSelector((keymap: OpenTuiKeymap) => - keymap - .getCommandEntries({ - visibility: "reachable", - namespace: "palette", - }) - .filter(isVisiblePaletteCommand), - ) - - const run = (command: string) => { - keymap.dispatchCommand(command) - } - - const slashes = createMemo(() => - entries().flatMap((entry) => { - const slashName = entry.command.slashName - if (typeof slashName !== "string" || !slashName) return [] - const slashAliases = entry.command.slashAliases - return { - display: `/${slashName}`, - description: - typeof entry.command.desc === "string" - ? entry.command.desc - : typeof entry.command.title === "string" - ? entry.command.title - : undefined, - aliases: Array.isArray(slashAliases) - ? slashAliases.filter((alias): alias is string => typeof alias === "string").map((alias) => `/${alias}`) - : undefined, - onSelect: () => run(entry.command.name), - } - }), - ) - - const value: CommandPaletteContext = { - run, - show() { - dialog.replace(() => ) - }, - slashes, - suspend(enabled: boolean) { - setSuspendCount((count) => Math.max(0, count + (enabled ? 1 : -1))) - }, - get suspended() { - return suspendCount() > 0 || dialog.stack.length > 0 - }, - matcher: reactiveMatcherFromSignal(() => suspendCount() === 0 && dialog.stack.length === 0), - } - - return {props.children} -} - -export function useCommandPalette() { - const value = useContext(ctx) - if (!value) throw new Error("CommandPalette context must be used within a CommandPaletteProvider") - return value -} - -function CommandPaletteDialog(props: { run(command: string): void }) { - const config = useTuiConfig() - const entries = useKeymapSelector((keymap: OpenTuiKeymap) => { - const query = { - namespace: "palette", - } - const reachable = keymap - .getCommandEntries({ - ...query, - visibility: "reachable", - }) - .filter(isVisiblePaletteCommand) - const registeredBindings = keymap.getCommandBindings({ - visibility: "registered", - commands: reachable.map((entry) => entry.command.name), - }) - - return reachable.map((entry) => ({ - ...entry, - bindings: registeredBindings.get(entry.command.name) ?? entry.bindings, - })) - }) - const options = createMemo(() => - entries().map((entry) => ({ - title: typeof entry.command.title === "string" ? entry.command.title : entry.command.name, - description: typeof entry.command.desc === "string" ? entry.command.desc : undefined, - category: typeof entry.command.category === "string" ? entry.command.category : undefined, - footer: formatKeyBindings(entry.bindings, config), - value: entry.command.name, - suggested: isSuggestedPaletteCommand(entry), - onSelect: (dialog: DialogContext) => { - dialog.clear() - props.run(entry.command.name) - }, - })), - ) - - let ref: DialogSelectRef - const list = () => { - if (ref?.filter) return options() - return [ - ...options() - .filter((option) => option.suggested) - .map((option) => ({ - ...option, - value: `suggested:${option.value}`, - category: "Suggested", - })), - ...options(), - ] - } - - return (ref = value)} title="Commands" options={list()} /> -} - -export function useCommandSlashes(): Accessor { - return useCommandPalette().slashes -} diff --git a/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts b/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts index b572302c8c..3a89b0ed7b 100644 --- a/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts +++ b/packages/opencode/src/cli/cmd/tui/context/editor-zed.ts @@ -195,6 +195,10 @@ export function resolveZedDbPath() { return candidates.find((item) => isFile(item)) } +export function isZedTerminal() { + return process.env.ZED_TERM === "true" || process.env.TERM_PROGRAM?.toLowerCase() === "zed" +} + function isFile(item: string) { try { return Filesystem.stat(item)?.isFile() === true diff --git a/packages/opencode/src/cli/cmd/tui/context/editor.ts b/packages/opencode/src/cli/cmd/tui/context/editor.ts index 8e2884abd1..598b01ee1c 100644 --- a/packages/opencode/src/cli/cmd/tui/context/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/context/editor.ts @@ -6,7 +6,7 @@ import { createStore } from "solid-js/store" import { Option, Schema, SchemaGetter } from "effect" import { isRecord } from "@/util/record" import { createSimpleContext } from "./helper" -import { resolveZedDbPath, resolveZedSelection } from "./editor-zed" +import { isZedTerminal, resolveZedDbPath, resolveZedSelection } from "./editor-zed" const MCP_PROTOCOL_VERSION = "2025-11-25" @@ -173,6 +173,12 @@ export const { use: useEditorContext, provider: EditorContextProvider } = create const connection = resolveEditorConnection(directory) if (!connection) { + if (!isZedTerminal()) { + setStore("status", "disabled") + scheduleReconnect() + return + } + const dbPath = resolveZedDbPath() if (!dbPath) { setStore("status", "disabled") @@ -311,7 +317,7 @@ export const { use: useEditorContext, provider: EditorContextProvider } = create return { enabled() { - return Boolean(resolveEditorConnection(directory) || resolveZedDbPath()) + return Boolean(resolveEditorConnection(directory) || (isZedTerminal() && resolveZedDbPath())) }, connected() { return store.status === "connected" diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 14a717f696..2fcc433927 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -49,6 +49,7 @@ type Theme = TuiThemeCurrent & { _hasSelectedListItemText: boolean } type ThemeColor = Exclude +type SyntaxStyleOverrides = Record export function selectedForeground(theme: Theme, bg?: RGBA): RGBA { // If theme explicitly defines selectedListItemText, use it @@ -718,16 +719,18 @@ export function generateSyntax(theme: Theme) { return SyntaxStyle.fromTheme(getSyntaxRules(theme)) } -export function generateSubtleSyntax(theme: Theme) { +export function generateSubtleSyntax(theme: Theme, overrides?: SyntaxStyleOverrides) { const rules = getSyntaxRules(theme) return SyntaxStyle.fromTheme( rules.map((rule) => { + const override = rule.scope.reduce((acc, scope) => ({ ...acc, ...overrides?.[scope] }), {}) if (rule.style.foreground) { const fg = rule.style.foreground return { ...rule, style: { ...rule.style, + ...override, foreground: RGBA.fromInts( Math.round(fg.r * 255), Math.round(fg.g * 255), @@ -773,7 +776,7 @@ function getSyntaxRules(theme: Theme) { { scope: ["extmark.paste"], style: { - foreground: theme.background, + foreground: selectedForeground(theme, theme.warning), background: theme.warning, bold: true, }, diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree-utils.ts b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree-utils.ts new file mode 100644 index 0000000000..a41c098461 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree-utils.ts @@ -0,0 +1,232 @@ +// Paths branch softly through the screen, +// A quiet tree of changed designs; +// Each leaf remembers what has been, +// And waits where careful light aligns. + +export type FileTreeItem = { + readonly file: string + readonly status?: "added" | "deleted" | "modified" +} + +export type FileTreeNode = { + readonly id: number + readonly name: string + readonly parent: number | undefined + readonly children: number[] + readonly depth: number + readonly kind: "directory" | "file" + readonly fileIndex?: number +} + +export type FileTree = { + readonly roots: number[] + readonly nodes: FileTreeNode[] +} + +export type FileTreeRow = { + readonly id: number + readonly depth: number + readonly kind: "directory" | "file" + readonly name: string + readonly fileIndex?: number +} + +export function buildFileTree(files: readonly FileTreeItem[]): FileTree { + const roots: number[] = [] + const nodes: FileTreeNode[] = [] + const directoryByPath = new Map() + + files.forEach((file, fileIndex) => { + const segments = file.file.split("/").filter(Boolean) + if (segments.length === 0) return + + const parent = segments.slice(0, -1).reduce( + (state, segment) => { + const directoryPath = state.path ? `${state.path}/${segment}` : segment + const existing = directoryByPath.get(directoryPath) + if (existing !== undefined) return { id: existing, path: directoryPath, depth: state.depth + 1 } + + const id = addFileTreeNode(nodes, roots, { + name: segment, + parent: state.id, + depth: state.depth, + kind: "directory", + }) + directoryByPath.set(directoryPath, id) + return { id, path: directoryPath, depth: state.depth + 1 } + }, + { id: undefined as number | undefined, path: "", depth: 0 }, + ) + + addFileTreeNode(nodes, roots, { + name: segments[segments.length - 1]!, + parent: parent.id, + depth: parent.depth, + kind: "file", + fileIndex, + }) + }) + + const tree = { roots, nodes } + tree.roots.sort((left, right) => compareFileTreeNodes(tree, left, right)) + tree.nodes.forEach((node) => node.children.sort((left, right) => compareFileTreeNodes(tree, left, right))) + return tree +} + +export function flattenFileTree(tree: FileTree, expanded?: ReadonlySet): FileTreeRow[] { + const rows: FileTreeRow[] = [] + const visit = (id: number, depth: number) => { + const node = tree.nodes[id]! + if (node.kind === "file") { + rows.push({ + id: node.id, + depth, + kind: node.kind, + name: node.name, + fileIndex: node.fileIndex, + }) + return + } + + const chain = collapsedFileTreeDirectoryChain(tree, node.id) + const last = chain[chain.length - 1]! + rows.push({ + id: node.id, + depth, + kind: node.kind, + name: chain.map((item) => item.name).join("/"), + fileIndex: node.fileIndex, + }) + if (!expanded || expanded.has(node.id)) last.children.forEach((child) => visit(child, depth + 1)) + } + tree.roots.forEach((root) => visit(root, 0)) + return rows +} + +function collapsedFileTreeDirectoryChain(tree: FileTree, id: number): FileTreeNode[] { + const node = tree.nodes[id]! + const child = node.children.length === 1 ? tree.nodes[node.children[0]!] : undefined + if (child?.kind !== "directory") return [node] + return [node, ...collapsedFileTreeDirectoryChain(tree, child.id)] +} + +export function compareFileTreeNodes(tree: FileTree, left: number, right: number) { + const leftNode = tree.nodes[left]! + const rightNode = tree.nodes[right]! + if (leftNode.kind !== rightNode.kind) return leftNode.kind === "directory" ? -1 : 1 + if (leftNode.name < rightNode.name) return -1 + if (leftNode.name > rightNode.name) return 1 + return left - right +} + +export function moveFileTreeSelection(rows: readonly FileTreeRow[], selected: number | undefined, offset: number) { + if (rows.length === 0) return undefined + const index = selected === undefined ? -1 : rows.findIndex((row) => row.id === selected) + if (index === -1) return rows[0]!.id + return rows[Math.max(0, Math.min(rows.length - 1, index + offset))]!.id +} + +export function moveFileTreeSelectionToFirstChild(rows: readonly FileTreeRow[], selected: number | undefined) { + const index = selected === undefined ? -1 : rows.findIndex((row) => row.id === selected) + const row = index === -1 ? undefined : rows[index] + if (row?.kind !== "directory") return selected + const child = rows[index + 1] + return child && child.depth > row.depth ? child.id : selected +} + +export function moveFileTreeSelectionToParent(rows: readonly FileTreeRow[], selected: number | undefined) { + const index = selected === undefined ? -1 : rows.findIndex((row) => row.id === selected) + const row = index === -1 ? undefined : rows[index] + if (!row || row.depth === 0) return selected + return rows.findLast((item, itemIndex) => itemIndex < index && item.depth < row.depth)?.id ?? selected +} + +export function moveFileTreeSelectionToFile( + rows: readonly FileTreeRow[], + selected: number | undefined, + offset: number, +) { + const fileRows = rows.filter((row) => row.fileIndex !== undefined) + if (fileRows.length === 0) return undefined + const selectedIndex = selected === undefined ? -1 : rows.findIndex((row) => row.id === selected) + if (selectedIndex === -1) return offset < 0 ? fileRows[fileRows.length - 1]!.id : fileRows[0]!.id + const next = + offset < 0 + ? fileRows.findLast((row) => rows.findIndex((item) => item.id === row.id) < selectedIndex) + : fileRows.find((row) => rows.findIndex((item) => item.id === row.id) > selectedIndex) + return next?.id ?? (offset < 0 ? fileRows[0]!.id : fileRows[fileRows.length - 1]!.id) +} + +export function fileTreeFileSelection(tree: FileTree, fileIndex: number) { + const node = tree.nodes.find((item) => item.kind === "file" && item.fileIndex === fileIndex) + if (!node) return undefined + return { + highlightedNode: node.id, + expandedNodes: fileTreeParentDirectories(tree, node.id), + } +} + +export function singlePatchFileIndex( + selected: number | undefined, + active: number | undefined, + current: number | undefined, + first: number | undefined, +) { + return selected ?? active ?? current ?? first +} + +export function orderedPatchFileIndexes(rows: readonly FileTreeRow[]) { + return rows.flatMap((row) => (row.fileIndex === undefined ? [] : [row.fileIndex])) +} + +export function showDiffViewerFileTree(showFileTree: boolean, fileCount: number) { + return showFileTree && fileCount > 0 +} + +export function movePatchFileIndex(fileIndexes: readonly number[], current: number | undefined, offset: number) { + if (fileIndexes.length === 0) return undefined + const index = current === undefined ? -1 : fileIndexes.indexOf(current) + if (index === -1) return fileIndexes[0] + return fileIndexes[Math.max(0, Math.min(fileIndexes.length - 1, index + offset))] +} + +export function allExpandedFileTreeDirectories(tree: FileTree) { + return new Set(tree.nodes.filter((node) => node.kind === "directory").map((node) => node.id)) +} + +export function toggleFileTreeDirectory(tree: FileTree, expanded: ReadonlySet, selected: number | undefined) { + if (selected === undefined || tree.nodes[selected]?.kind !== "directory") return expanded + const next = new Set(expanded) + if (next.has(selected)) next.delete(selected) + else next.add(selected) + return next +} + +export function setFileTreeDirectoryExpanded( + tree: FileTree, + expanded: ReadonlySet, + selected: number | undefined, + value: boolean, +) { + if (selected === undefined || tree.nodes[selected]?.kind !== "directory") return expanded + const next = new Set(expanded) + if (value) next.add(selected) + else next.delete(selected) + return next +} + +function addFileTreeNode(nodes: FileTreeNode[], roots: number[], input: Omit) { + const id = nodes.length + nodes.push({ ...input, id, children: [] }) + if (input.parent === undefined) roots.push(id) + else nodes[input.parent]!.children.push(id) + return id +} + +function fileTreeParentDirectories(tree: FileTree, id: number) { + const result = new Set() + for (let parent = tree.nodes[id]?.parent; parent !== undefined; parent = tree.nodes[parent]?.parent) { + result.add(parent) + } + return result +} diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree.tsx new file mode 100644 index 0000000000..89dcc00937 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-file-tree.tsx @@ -0,0 +1,162 @@ +/** @jsxImportSource @opentui/solid */ +import type { ColorInput, RGBA, ScrollBoxRenderable } from "@opentui/core" +import { Locale } from "@/util/locale" +import { tint } from "@tui/context/theme" +import { createEffect, createMemo, For, Match, Switch } from "solid-js" +import { buildFileTree, flattenFileTree, type FileTreeItem, type FileTreeRow } from "./diff-viewer-file-tree-utils" +import { Panel } from "./diff-viewer-ui" + +const FILE_TREE_STATUS_WIDTH = 2 + +export type DiffViewerFileTreeTheme = { + readonly background: RGBA + readonly backgroundPanel: ColorInput + readonly backgroundElement: ColorInput + readonly primary: ColorInput + readonly secondary: ColorInput + readonly selectedListItemText: ColorInput + readonly text: RGBA + readonly textMuted: RGBA + readonly error: ColorInput +} + +export type DiffViewerFileTreeProps = { + readonly width: number + readonly files: readonly FileTreeItem[] + readonly loading: boolean + readonly error: unknown + readonly theme: DiffViewerFileTreeTheme + readonly focused?: boolean + readonly highlightedNode?: number + readonly selectedFileIndex?: number + readonly reviewedFileNames?: ReadonlySet + readonly expandedNodes?: ReadonlySet + readonly onRowClick?: (row: FileTreeRow) => void +} + +export function DiffViewerFileTree(props: DiffViewerFileTreeProps) { + const tree = createMemo(() => buildFileTree(props.files)) + const rows = createMemo(() => flattenFileTree(tree(), props.expandedNodes)) + let scroll: ScrollBoxRenderable | undefined + + createEffect(() => { + const node = props.highlightedNode + if (node === undefined) return + const selectedIndex = rows().findIndex((row) => row.id === node) + if (selectedIndex === -1) return + const scrollSelectedIntoView = () => scrollFileTreeRowIntoView(scroll, selectedIndex) + scrollSelectedIntoView() + requestAnimationFrame(scrollSelectedIntoView) + }) + + const fadedColor = () => tint(props.theme.text, props.theme.background, 0.75) + + return ( + + (scroll = element)} + verticalScrollbarOptions={{ visible: false }} + horizontalScrollbarOptions={{ visible: false }} + > + + + + + + No files + + 0}> + + {(row, index) => { + const highlighted = () => props.focused && props.highlightedNode === row.id + const selected = () => row.fileIndex !== undefined && props.selectedFileIndex === row.fileIndex + const reviewed = () => { + const file = row.fileIndex === undefined ? undefined : props.files[row.fileIndex]?.file + return file !== undefined && (props.reviewedFileNames?.has(file) ?? false) + } + const prefix = () => fileTreeRowPrefix(rows(), index(), row, props.expandedNodes) + const status = () => fileTreeRowStatus(row, props.files, reviewed()) + const name = () => + Locale.truncate(row.name, Math.max(1, props.width - FILE_TREE_STATUS_WIDTH - prefix().length)) + return ( + props.onRowClick?.(row)} + > + + {prefix()} + + + + {name()} + + + + {status()} + + + ) + }} + + + + + + ) +} + +function scrollFileTreeRowIntoView(scroll: ScrollBoxRenderable | undefined, index: number) { + if (!scroll) return + if (index < scroll.scrollTop) { + scroll.scrollTo(index) + return + } + if (index >= scroll.scrollTop + scroll.viewport.height) { + scroll.scrollTo(index - scroll.viewport.height + 1) + } +} + +function fileTreeRowPrefix( + rows: readonly FileTreeRow[], + index: number, + row: FileTreeRow, + expandedNodes: ReadonlySet | undefined, +) { + const indentation = Array.from({ length: row.depth }, (_, depth) => { + if (depth === 0 && !hasLaterSibling(rows, 0, 0)) return " " + return hasLaterSibling(rows, index, depth) ? "│ " : " " + }).join("") + const topRoot = index === 0 && row.depth === 0 + const branch = topRoot ? " " : hasLaterSibling(rows, index, row.depth) ? "├─ " : "└─ " + const marker = row.kind === "directory" ? (expandedNodes && !expandedNodes.has(row.id) ? "▸ " : "▾ ") : "" + + return `${indentation}${branch}${marker}` +} + +function hasLaterSibling(rows: readonly FileTreeRow[], index: number, depth: number) { + return rows.slice(index + 1).find((row) => row.depth <= depth)?.depth === depth +} + +function fileTreeRowStatus(row: FileTreeRow, files: readonly FileTreeItem[], reviewed: boolean) { + if (row.fileIndex === undefined) return "" + const status = files[row.fileIndex]?.status + const marker = status === "modified" ? "M" : status === "added" ? "A" : status === "deleted" ? "D" : "?" + return `${reviewed ? "✓" : " "}${marker}`.padStart(FILE_TREE_STATUS_WIDTH) +} diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-ui.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-ui.tsx new file mode 100644 index 0000000000..30d5f30389 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer-ui.tsx @@ -0,0 +1,103 @@ +import type { BorderSides, ColorInput } from "@opentui/core" +import type { JSX } from "@opentui/solid" +import { useTheme } from "@tui/context/theme" +import { createContext, Show, splitProps, useContext } from "solid-js" + +export type Axis = "x" | "y" +export type SeparatorEdge = "edge" | "edge-in" | "edge-out" +export type PanelBorder = "start" | "end" | "both" | "none" + +const PanelGroupContext = createContext<{ axis: Axis }>() + +function crossAxis(axis: Axis) { + return axis === "x" ? "y" : "x" +} + +function usePanelGroup() { + return useContext(PanelGroupContext) +} + +export function PanelGroup(props: JSX.IntrinsicElements["box"] & { axis: Axis }) { + const [local, boxProps] = splitProps(props, ["axis", "children"]) + return ( + + + {local.children} + + + ) +} + +export function Panel(props: Omit & { border?: PanelBorder }) { + const group = usePanelGroup() + const { theme } = useTheme() + const [local, boxProps] = splitProps(props, ["border"]) + const border = local.border ?? "start" + const borderProps = + border === "none" + ? {} + : { + border: panelBorderSides(group?.axis ?? "y", border), + borderColor: theme.border, + } + + return ( + + ) +} + +function panelBorderSides(axis: Axis, border: Exclude): BorderSides[] { + if (axis === "x") return border === "both" ? ["top", "bottom"] : [border === "start" ? "top" : "bottom"] + return border === "both" ? ["left", "right"] : [border === "start" ? "left" : "right"] +} + +export function Separator(props: { axis?: Axis; color?: ColorInput; start?: SeparatorEdge; end?: SeparatorEdge }) { + const group = usePanelGroup() + const { theme } = useTheme() + const color = () => props.color ?? theme.border + const axis = () => props.axis ?? crossAxis(group?.axis ?? "y") + if (axis() === "y") { + return ( + } + > + + {(edge) => {verticalEdge(edge(), "start")}} + + {(edge) => {verticalEdge(edge(), "end")}} + + + ) + } + return ( + } + > + + {(edge) => {horizontalEdge(edge(), "start")}} + + {(edge) => {horizontalEdge(edge(), "end")}} + + + ) +} + +function horizontalEdge(edge: SeparatorEdge, side: "start" | "end") { + if (edge === "edge") return side === "start" ? "├" : "┤" + if (edge === "edge-in") return "┴" + return "┬" +} + +function verticalEdge(edge: SeparatorEdge, side: "start" | "end") { + if (edge === "edge") return side === "start" ? "┬" : "┴" + if (edge === "edge-in") return "┤" + return "├" +} diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx new file mode 100644 index 0000000000..1eb30b0b98 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/diff-viewer.tsx @@ -0,0 +1,959 @@ +/** @jsxImportSource @opentui/solid */ +import type { TuiPlugin, TuiPluginApi, TuiRouteCurrent } from "@kilocode/plugin/tui" +import type { SnapshotFileDiff, VcsFileDiff } from "@kilocode/sdk/v2" +import { TextAttributes, type BorderSides, type BoxRenderable, type ScrollBoxRenderable } from "@opentui/core" +import { LANGUAGE_EXTENSIONS } from "@/lsp/language" +import { useBindings, useCommandShortcut } from "@tui/keymap" +import { useTheme } from "@tui/context/theme" +import { useTerminalDimensions } from "@opentui/solid" +import path from "path" +import { createEffect, createMemo, createResource, createSignal, For, Match, onCleanup, Show, Switch } from "solid-js" +import { DiffViewerFileTree } from "./diff-viewer-file-tree" +import { Panel, PanelGroup, Separator } from "./diff-viewer-ui" +import { DialogSelect } from "@tui/ui/dialog-select" +import { + allExpandedFileTreeDirectories, + buildFileTree, + fileTreeFileSelection, + type FileTreeRow, + flattenFileTree, + moveFileTreeSelection, + moveFileTreeSelectionToFirstChild, + moveFileTreeSelectionToParent, + movePatchFileIndex, + orderedPatchFileIndexes, + setFileTreeDirectoryExpanded, + showDiffViewerFileTree, + singlePatchFileIndex, + toggleFileTreeDirectory, +} from "./diff-viewer-file-tree-utils" + +const ROUTE = "diff" +const MIN_SPLIT_WIDTH = 100 +const FILE_TREE_WIDTH = 32 +const PLAIN_TEXT_FILETYPE = "opencode-plain-text" +const WORKING_TREE_DIFF_CONTEXT_LINES = 12 +const KV_SHOW_FILE_TREE = "diff_viewer_show_file_tree" +const KV_SINGLE_PATCH = "diff_viewer_single_patch" +const KV_VIEW = "diff_viewer_view" +type DiffMode = "git" | "last-turn" +type DiffViewerFocus = "patches" | "files" +type DiffView = "split" | "unified" + +type DiffFile = { + readonly file: string + readonly patch?: string + readonly additions: number + readonly deletions: number + readonly status: "added" | "deleted" | "modified" +} + +const normalizeDiffs = (diffs: readonly (VcsFileDiff | SnapshotFileDiff)[]): DiffFile[] => + diffs.flatMap((item) => + item.file + ? [ + { + file: item.file, + patch: item.patch, + additions: item.additions, + deletions: item.deletions, + status: item.status ?? "modified", + } satisfies DiffFile, + ] + : [], + ) + +function filetype(input?: string) { + if (!input) return "none" + const language = LANGUAGE_EXTENSIONS[path.extname(input)] + if (["typescriptreact", "javascriptreact", "javascript"].includes(language)) return "typescript" + return language +} + +function storedView(value: unknown): DiffView | undefined { + if (value === "split" || value === "unified") return value +} + +function DiffViewer(props: { api: TuiPluginApi }) { + const dimensions = useTerminalDimensions() + const themeState = useTheme() + const theme = () => props.api.theme.current + const params = () => + ("params" in props.api.route.current ? props.api.route.current.params : undefined) as + | { + mode?: DiffMode + sessionID?: string + messageID?: string + returnRoute?: TuiRouteCurrent + } + | undefined + const mode = () => params()?.mode ?? "git" + const diffInput = createMemo(() => ({ + mode: mode(), + sessionID: params()?.sessionID, + messageID: params()?.messageID, + })) + const [diff] = createResource(diffInput, async (input) => { + if (input.mode === "last-turn") { + const sessionID = input.sessionID + if (!sessionID) return [] + const result = await props.api.client.session.diff( + { sessionID, messageID: input.messageID }, + { throwOnError: true }, + ) + return normalizeDiffs(result.data ?? []) + } + + const result = await props.api.client.vcs.diff( + { mode: "git", context: WORKING_TREE_DIFF_CONTEXT_LINES }, + { throwOnError: true }, + ) + return normalizeDiffs(result.data ?? []) + }) + const files = createMemo(() => diff() ?? []) + const [focus, setFocus] = createSignal("patches") + const [fileTreeEnabled, setFileTreeEnabled] = createSignal( + props.api.kv.get(KV_SHOW_FILE_TREE, true) !== false, + ) + const showFileTree = createMemo(() => showDiffViewerFileTree(fileTreeEnabled(), files().length)) + const [singlePatch, setSinglePatch] = createSignal(props.api.kv.get(KV_SINGLE_PATCH, false) === true) + const patchPaneWidth = createMemo(() => dimensions().width - (showFileTree() ? 33 : 0) - 4) + const patchLeftBorder = createMemo(() => (showFileTree() ? ["left"] : [])) + const splitAvailable = createMemo(() => patchPaneWidth() >= MIN_SPLIT_WIDTH) + const defaultView = createMemo(() => { + if (props.api.tuiConfig.diff_style === "stacked") return "unified" + return splitAvailable() ? "split" : "unified" + }) + const [viewOverride, setViewOverride] = createSignal(storedView(props.api.kv.get(KV_VIEW))) + const view = createMemo(() => (splitAvailable() ? (viewOverride() ?? defaultView()) : "unified")) + const fileTree = createMemo(() => buildFileTree(files())) + const [expandedFileNodes, setExpandedFileNodes] = createSignal>(new Set()) + const [highlightedFileNode, setHighlightedFileNode] = createSignal() + const [lastHighlightedFileNode, setLastHighlightedFileNode] = createSignal() + const [activePatchFileIndex, setActivePatchFileIndex] = createSignal() + const [selectedFileIndex, setSelectedFileIndex] = createSignal() + const [reviewedFileNames, setReviewedFileNames] = createSignal>(new Set()) + const fileRows = createMemo(() => flattenFileTree(fileTree(), expandedFileNodes())) + const patchFileIndexes = createMemo(() => orderedPatchFileIndexes(flattenFileTree(fileTree()))) + const focusRunner = (input: Record void>) => () => input[focus()]() + const switchFocusShortcut = useCommandShortcut("diff.switch_focus") + const nextFileShortcut = useCommandShortcut("diff.next_file") + const previousFileShortcut = useCommandShortcut("diff.previous_file") + const toggleFileTreeShortcut = useCommandShortcut("diff.toggle_file_tree") + const singlePatchShortcut = useCommandShortcut("diff.single_patch") + const switchSourceShortcut = useCommandShortcut("diff.switch_source") + const toggleViewShortcut = useCommandShortcut("diff.toggle_view") + const markReviewedShortcut = useCommandShortcut("diff.mark_reviewed") + const helpShortcut = useCommandShortcut("diff.help") + let scroll: ScrollBoxRenderable | undefined + const patchNodeByFileIndex = new Map() + const [pendingPatchScrollFileIndex, setPendingPatchScrollFileIndex] = createSignal() + const [patchFillerHeight, setPatchFillerHeight] = createSignal(0) + + onCleanup(() => props.api.ui.dialog.clear()) + + createEffect(() => { + setExpandedFileNodes(allExpandedFileTreeDirectories(fileTree())) + setHighlightedFileNode(undefined) + setLastHighlightedFileNode(undefined) + setActivePatchFileIndex(undefined) + setSelectedFileIndex(undefined) + setReviewedFileNames(new Set()) + }) + + const ensureHighlightedFileNode = () => { + const highlighted = highlightedFileNode() + if (highlighted !== undefined && fileRows().some((row) => row.id === highlighted)) return + const lastHighlighted = lastHighlightedFileNode() + const next = + lastHighlighted !== undefined && fileRows().some((row) => row.id === lastHighlighted) + ? lastHighlighted + : fileRows().find((row) => row.fileIndex !== undefined)?.id + setHighlightedFileNode(next) + } + + const setHighlighted = (node: number | undefined) => { + setHighlightedFileNode(node) + if (node !== undefined) setLastHighlightedFileNode(node) + } + + const moveFileSelection = (offset: number) => + setHighlighted(moveFileTreeSelection(fileRows(), highlightedFileNode(), offset)) + + const clearFileTreePatchState = () => { + setHighlightedFileNode(undefined) + setActivePatchFileIndex(undefined) + } + + const scrollPatchNodeToTop = (patchNode: BoxRenderable) => { + requestAnimationFrame(() => { + if (!scroll) return + const scrollDelta = patchNode.y - scroll.viewport.y + const contentY = scroll.scrollTop + scrollDelta + const offset = contentY === 0 ? 0 : 1 + scroll.scrollBy(scrollDelta + offset) + }) + } + + const revealFileTreeFile = (fileIndex: number) => { + const selection = fileTreeFileSelection(fileTree(), fileIndex) + if (!selection) return + setExpandedFileNodes((expanded) => { + const next = new Set(expanded) + selection.expandedNodes.forEach((node) => next.add(node)) + return next + }) + setHighlighted(selection.highlightedNode) + } + + const selectPatchFile = (fileIndex: number) => { + revealFileTreeFile(fileIndex) + setActivePatchFileIndex(fileIndex) + setSelectedFileIndex(fileIndex) + } + + const scrollToFileIndex = (fileIndex: number | undefined) => { + if (fileIndex === undefined) return + selectPatchFile(fileIndex) + const patchNode = patchNodeByFileIndex.get(fileIndex) + if (patchNode) scrollPatchNodeToTop(patchNode) + } + + const jumpToFileIndex = (fileIndex: number | undefined) => { + if (fileIndex === undefined) return + scrollToFileIndex(fileIndex) + } + + const currentPatchFileIndex = () => { + if (!scroll) return undefined + const viewportContentY = scroll.scrollTop + 1 + const entries = patchFileIndexes() + .map((fileIndex) => ({ + fileIndex, + node: patchNodeByFileIndex.get(fileIndex), + })) + .filter((entry): entry is { fileIndex: number; node: BoxRenderable } => Boolean(entry.node)) + .map((entry) => ({ + ...entry, + contentY: scroll!.scrollTop + entry.node.y - scroll!.viewport.y, + })) + .sort((left, right) => left.contentY - right.contentY) + return entries.findLast((entry) => entry.contentY <= viewportContentY)?.fileIndex ?? entries[0]?.fileIndex + } + + const jumpRelativePatchFile = (offset: number) => { + const next = movePatchFileIndex(patchFileIndexes(), selectedFileIndex() ?? activePatchFileIndex(), offset) + if (singlePatch()) { + if (next === undefined) return + selectPatchFile(next) + scrollSinglePatchToTop() + return + } + scrollToFileIndex(next) + } + + const highlightedPatchFileIndex = () => fileRows().find((row) => row.id === highlightedFileNode())?.fileIndex + const firstPatchFileIndex = () => fileRows().find((row) => row.fileIndex !== undefined)?.fileIndex + const visiblePatchFiles = createMemo(() => { + if (!singlePatch()) { + return patchFileIndexes().flatMap((fileIndex) => { + const file = files()[fileIndex] + return file ? [{ file, fileIndex }] : [] + }) + } + const fileIndex = singlePatchFileIndex( + selectedFileIndex(), + activePatchFileIndex(), + currentPatchFileIndex(), + firstPatchFileIndex(), + ) + const file = fileIndex === undefined ? undefined : files()[fileIndex] + return file && fileIndex !== undefined ? [{ file, fileIndex }] : [] + }) + + const ensureHighlightedPatchFile = () => { + const fileIndex = currentPatchFileIndex() ?? activePatchFileIndex() ?? firstPatchFileIndex() + if (fileIndex === undefined) return + selectPatchFile(fileIndex) + } + + const scrollToPatchFileIndexAfterRender = (fileIndex: number) => { + setPendingPatchScrollFileIndex(fileIndex) + requestAnimationFrame(() => { + const patchNode = patchNodeByFileIndex.get(fileIndex) + if (patchNode) scrollPatchNodeToTop(patchNode) + requestAnimationFrame(() => { + const patchNode = patchNodeByFileIndex.get(fileIndex) + if (patchNode) scrollPatchNodeToTop(patchNode) + setPendingPatchScrollFileIndex(undefined) + }) + }) + } + + const scrollSinglePatchToTop = () => { + requestAnimationFrame(() => { + scroll?.scrollTo(0) + requestAnimationFrame(() => scroll?.scrollTo(0)) + }) + } + + const measurePatchFiller = () => { + requestAnimationFrame(() => { + if (!scroll) return + const entries = visiblePatchFiles() + .map((entry) => patchNodeByFileIndex.get(entry.fileIndex)) + .filter((node): node is BoxRenderable => Boolean(node)) + if (entries.length === 0) { + setPatchFillerHeight(0) + return + } + const contentHeight = Math.max( + ...entries.map((node) => scroll!.scrollTop + node.y - scroll!.viewport.y + node.height), + ) + setPatchFillerHeight(Math.max(0, scroll.viewport.height - contentHeight)) + }) + } + + const registerPatchNode = (fileIndex: number, element: BoxRenderable) => { + patchNodeByFileIndex.set(fileIndex, element) + measurePatchFiller() + if (pendingPatchScrollFileIndex() !== fileIndex) return + requestAnimationFrame(() => { + scrollPatchNodeToTop(element) + requestAnimationFrame(() => { + scrollPatchNodeToTop(element) + setPendingPatchScrollFileIndex(undefined) + }) + }) + } + + createEffect(() => { + visiblePatchFiles() + dimensions() + view() + measurePatchFiller() + }) + + const toggleSelectedFileTreeRow = () => { + const highlighted = fileRows().find((row) => row.id === highlightedFileNode()) + if (highlighted?.fileIndex !== undefined) { + jumpToFileIndex(highlighted.fileIndex) + return + } + setExpandedFileNodes((expanded) => toggleFileTreeDirectory(fileTree(), expanded, highlightedFileNode())) + } + + const clickFileTreeRow = (row: FileTreeRow) => { + setFocus("files") + setHighlighted(row.id) + if (row.fileIndex !== undefined) { + jumpToFileIndex(row.fileIndex) + return + } + setExpandedFileNodes((expanded) => toggleFileTreeDirectory(fileTree(), expanded, row.id)) + } + + const toggleSelectedFileReviewed = () => { + const fileIndex = + focus() === "files" + ? fileRows().find((row) => row.id === highlightedFileNode())?.fileIndex + : (selectedFileIndex() ?? activePatchFileIndex() ?? currentPatchFileIndex()) + const file = fileIndex === undefined ? undefined : files()[fileIndex]?.file + if (!file) return + setReviewedFileNames((reviewed) => { + const next = new Set(reviewed) + if (next.has(file)) next.delete(file) + else next.add(file) + return next + }) + } + + const commands = [ + { + name: "diff.close", + title: "Close diff viewer", + category: "VCS", + run() { + const returnRoute = params()?.returnRoute + props.api.ui.dialog.clear() + + props.api.route.navigate( + returnRoute?.name ?? "home", + returnRoute && "params" in returnRoute ? returnRoute.params : undefined, + ) + }, + }, + { + name: "diff.down", + title: "Move diff viewer down", + category: "VCS", + run: focusRunner({ + files() { + moveFileSelection(1) + }, + patches() { + clearFileTreePatchState() + scroll?.scrollBy(1) + }, + }), + }, + { + name: "diff.up", + title: "Move diff viewer up", + category: "VCS", + run: focusRunner({ + files() { + moveFileSelection(-1) + }, + patches() { + clearFileTreePatchState() + scroll?.scrollBy(-1) + }, + }), + }, + { + name: "diff.page.down", + title: "Page diff viewer down", + category: "VCS", + run: focusRunner({ + files() { + moveFileSelection(8) + }, + patches() { + clearFileTreePatchState() + if (scroll) scroll.scrollBy(scroll.height) + }, + }), + }, + { + name: "diff.page.up", + title: "Page diff viewer up", + category: "VCS", + run: focusRunner({ + files() { + moveFileSelection(-8) + }, + patches() { + clearFileTreePatchState() + if (scroll) scroll.scrollBy(-scroll.height) + }, + }), + }, + { + name: "diff.toggle", + title: "Toggle diff viewer item", + category: "VCS", + run: focusRunner({ + files() { + toggleSelectedFileTreeRow() + }, + patches() {}, + }), + }, + { + name: "diff.expand", + title: "Expand diff viewer item", + category: "VCS", + run: focusRunner({ + files() { + const highlighted = highlightedFileNode() + if (highlighted !== undefined && expandedFileNodes().has(highlighted)) { + setHighlighted(moveFileTreeSelectionToFirstChild(fileRows(), highlighted)) + return + } + setExpandedFileNodes((expanded) => + setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), true), + ) + }, + patches() {}, + }), + }, + { + name: "diff.expand_all", + title: "Expand all diff viewer folders", + category: "VCS", + run: focusRunner({ + files() { + setExpandedFileNodes(allExpandedFileTreeDirectories(fileTree())) + }, + patches() {}, + }), + }, + { + name: "diff.collapse", + title: "Collapse diff viewer item", + category: "VCS", + run: focusRunner({ + files() { + const highlighted = highlightedFileNode() + const node = highlighted === undefined ? undefined : fileTree().nodes[highlighted] + if (node?.kind !== "directory" || !expandedFileNodes().has(node.id)) { + setHighlighted(moveFileTreeSelectionToParent(fileRows(), highlighted)) + return + } + setExpandedFileNodes((expanded) => + setFileTreeDirectoryExpanded(fileTree(), expanded, highlightedFileNode(), false), + ) + }, + patches() {}, + }), + }, + { + name: "diff.next_file", + title: "Jump to next diff file", + category: "VCS", + run() { + jumpRelativePatchFile(1) + }, + }, + { + name: "diff.previous_file", + title: "Jump to previous diff file", + category: "VCS", + run() { + jumpRelativePatchFile(-1) + }, + }, + { + name: "diff.mark_reviewed", + title: "Toggle selected diff file reviewed", + category: "VCS", + run() { + toggleSelectedFileReviewed() + }, + }, + { + name: "diff.switch_focus", + title: "Switch diff viewer focus", + category: "VCS", + run() { + if (!showFileTree()) return + setFocus((current) => { + if (current === "files") return "patches" + ensureHighlightedFileNode() + return "files" + }) + }, + }, + { + name: "diff.toggle_file_tree", + title: "Toggle diff viewer file tree", + category: "VCS", + run() { + const next = !fileTreeEnabled() + if (!next) setFocus("patches") + setFileTreeEnabled(next) + props.api.kv.set(KV_SHOW_FILE_TREE, next) + }, + }, + { + name: "diff.single_patch", + title: "Toggle single patch view", + category: "VCS", + run() { + if (!singlePatch()) { + ensureHighlightedPatchFile() + setSinglePatch(true) + props.api.kv.set(KV_SINGLE_PATCH, true) + scrollSinglePatchToTop() + return + } + const fileIndex = + visiblePatchFiles()[0]?.fileIndex ?? + singlePatchFileIndex( + selectedFileIndex(), + activePatchFileIndex(), + currentPatchFileIndex(), + firstPatchFileIndex(), + ) + if (fileIndex !== undefined) selectPatchFile(fileIndex) + setSinglePatch(false) + props.api.kv.set(KV_SINGLE_PATCH, false) + if (fileIndex !== undefined) scrollToPatchFileIndexAfterRender(fileIndex) + }, + }, + { + name: "diff.switch_source", + title: "Switch diff viewer source", + category: "VCS", + run() { + openSwitchDiffDialog() + }, + }, + { + name: "diff.toggle_view", + title: "Toggle diff viewer split or unified view", + category: "VCS", + run() { + if (!splitAvailable()) return + const next = view() === "split" ? "unified" : "split" + setViewOverride(next) + props.api.kv.set(KV_VIEW, next) + }, + }, + { + name: "diff.help", + title: "Show more diff viewer shortcuts", + category: "VCS", + run() { + openHelpDialog() + }, + }, + ] + + const switchDiffOptions = createMemo(() => [ + { + title: "Working tree", + value: "git" as const, + description: "Show current git changes", + }, + { + title: "Last turn", + value: "last-turn" as const, + description: "Show changes from the last assistant turn", + }, + ]) + + const openSwitchDiffDialog = () => { + props.api.ui.dialog.replace(() => ( + ({ + ...option, + onSelect(dialog) { + dialog.clear() + props.api.route.navigate(ROUTE, { + mode: option.value, + sessionID: params()?.sessionID, + messageID: params()?.messageID, + returnRoute: params()?.returnRoute, + }) + }, + }))} + /> + )) + } + + const openHelpDialog = () => { + props.api.ui.dialog.replace(() => ) + props.api.ui.dialog.setSize("large") + } + + useBindings(() => ({ + commands, + bindings: [ + { key: "j,down", cmd: "diff.down", desc: "Move diff viewer down" }, + { key: "k,up", cmd: "diff.up", desc: "Move diff viewer up" }, + { key: "pagedown,ctrl+f", cmd: "diff.page.down", desc: "Page diff viewer down" }, + { key: "pageup,ctrl+b", cmd: "diff.page.up", desc: "Page diff viewer up" }, + { key: "m", cmd: "diff.mark_reviewed", desc: "Mark selected file reviewed" }, + ...props.api.tuiConfig.keybinds.gather( + "diff", + commands.map((command) => command.name), + ), + ], + })) + + return ( + + + + Diff + {mode() === "last-turn" ? "last turn" : "working tree"} + + + {files().length} {files().length === 1 ? "file" : "files"} + + + + + + + + + Loading diff... + + + + + + No diff! + + + + + + Failed to load diff + + + + + + + + + + + (scroll = element)} + flexGrow={1} + minHeight={0} + verticalScrollbarOptions={{ visible: false }} + horizontalScrollbarOptions={{ visible: false }} + > + + {(entry, index) => { + const reviewed = () => reviewedFileNames().has(entry.file.file) + return ( + registerPatchNode(entry.fileIndex, element)}> + {index() !== 0 ? : null} + + {entry.file.file} + + + +{entry.file.additions} + + + -{entry.file.deletions} + + + + No patch available for this file.} + > + {(patch) => ( + + + + )} + + + ) + }} + + 0}> + + + + + + + + + + + + + {(shortcut) => ( + + {shortcut()} focus file tree + + )} + + + {(shortcut) => ( + + {shortcut()} next file + + )} + + + {(shortcut) => ( + + {shortcut()} previous file + + )} + + + {(shortcut) => ( + + {shortcut()} switch source + + )} + + + {(shortcut) => ( + + {shortcut()} mark reviewed + + )} + + + {(shortcut) => ( + + {shortcut()} all + + )} + + + + + ) +} + +function DiffViewerHelpDialog() { + const { theme } = useTheme() + const rows = [ + { + shortcut: () => "q", + action: "Close viewer", + description: "Quit the diff viewer", + }, + { + shortcut: useCommandShortcut("diff.switch_focus"), + action: "Focus file tree", + description: "Move keyboard focus between the file tree and patch pane", + }, + { + shortcut: useCommandShortcut("diff.next_file"), + action: "Next file", + description: "Select the next changed file in file-tree order", + }, + { + shortcut: useCommandShortcut("diff.previous_file"), + action: "Previous file", + description: "Select the previous changed file in file-tree order", + }, + { + shortcut: useCommandShortcut("diff.toggle_file_tree"), + action: "Toggle file tree", + description: "Show or hide the file tree sidebar", + }, + { + shortcut: useCommandShortcut("diff.single_patch"), + action: "Toggle patches", + description: "Switch between one selected patch and all patches", + }, + { + shortcut: useCommandShortcut("diff.switch_source"), + action: "Switch source", + description: "Choose working tree or last-turn changes", + }, + { + shortcut: useCommandShortcut("diff.toggle_view"), + action: "Toggle view", + description: "Switch between split and unified diff layout", + }, + { + shortcut: useCommandShortcut("diff.expand_all"), + action: "Expand all folders", + description: "Open every folder in the file tree", + }, + { + shortcut: useCommandShortcut("diff.mark_reviewed"), + action: "Mark reviewed", + description: "Toggle reviewed state for the selected file", + }, + ] + + return ( + + + + Diff shortcuts + + esc + + + + Key + + + Action + + Description + + + {(row) => ( + + + {row.shortcut() || "-"} + + + {row.action} + + {row.description} + + )} + + + ) +} + +const tui: TuiPlugin = async (api) => { + api.route.register([ + { + name: ROUTE, + render: () => , + }, + ]) + + api.keymap.registerLayer({ + commands: [ + { + name: "diff.open", + title: "Open diff viewer", + slashName: "diff", + category: "VCS", + namespace: "palette", + run() { + api.route.navigate(ROUTE, { + mode: "git", + sessionID: "params" in api.route.current ? api.route.current.params?.sessionID : undefined, + returnRoute: api.route.current, + }) + api.ui.dialog.clear() + }, + }, + ], + }) +} + +export default { + id: "diff-viewer", + tui, +} diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx index 130bfa71e3..f2887ba221 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx @@ -24,12 +24,12 @@ import type { SessionMessageCompaction, SessionMessageModelSwitched, SessionMessageShell, - SessionMessageSynthetic, SessionMessageUser, ToolFileContent, ToolTextContent, } from "@kilocode/sdk/v2" import { createEffect, createMemo, createSignal, For, Match, Show, Switch } from "solid-js" +import { collapseToolOutput } from "../../util/collapse-tool-output" const id = "internal:session-v2-debug" const route = "session.v2.messages" @@ -198,26 +198,28 @@ function UserMessage(props: { message: SessionMessageUser; index: number }) { function ShellMessage(props: { message: SessionMessageShell }) { const { theme } = useTheme() + const dimensions = useTerminalDimensions() const output = createMemo(() => stripAnsi(props.message.output.trim())) const [expanded, setExpanded] = createSignal(false) - const lines = createMemo(() => output().split("\n")) - const overflow = createMemo(() => lines().length > 10) + const maxLines = 10 + const maxChars = createMemo(() => maxLines * Math.max(20, dimensions().width - 6)) + const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars())) const limited = createMemo(() => { - if (expanded() || !overflow()) return output() - return [...lines().slice(0, 10), "…"].join("\n") + if (expanded() || !collapsed().overflow) return output() + return collapsed().output }) return ( setExpanded((prev) => !prev) : undefined} + onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined} > $ {props.message.command} {limited()} - + {expanded() ? "Click to collapse" : "Click to expand"} @@ -407,22 +409,13 @@ function AssistantReasoning(props: { - + @@ -430,9 +423,7 @@ function AssistantReasoning(props: { - - {title() ? "▶ Thought: " + title() : "▶ Thought"} - + @@ -445,6 +436,16 @@ function AssistantReasoning(props: { ) } +function CollapsedReasoningText(props: { title: string | null }) { + const { theme } = useTheme() + + return ( + + {props.title ? "+ Thought: " + props.title : "+ Thought"} + + ) +} + function AssistantTool(props: { part: SessionMessageAssistantTool; sessionID: string }) { const input = createMemo(() => toolInputRecord(props.part.state.input)) const toolprops = { @@ -518,14 +519,15 @@ type ToolProps = { function GenericTool(props: ToolProps) { const { theme } = useTheme() + const dimensions = useTerminalDimensions() const output = createMemo(() => props.output?.trim() ?? "") const [expanded, setExpanded] = createSignal(false) - const lines = createMemo(() => output().split("\n")) const maxLines = 3 - const overflow = createMemo(() => lines().length > maxLines) + const maxChars = createMemo(() => maxLines * Math.max(20, dimensions().width - 6)) + const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars())) const limited = createMemo(() => { - if (expanded() || !overflow()) return output() - return [...lines().slice(0, maxLines), "…"].join("\n") + if (expanded() || !collapsed().overflow) return output() + return collapsed().output }) return ( setExpanded((prev) => !prev) : undefined} + onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined} > {limited()} - + {expanded() ? "Click to collapse" : "Click to expand"} @@ -702,15 +704,17 @@ function BlockTool(props: { function Bash(props: ToolProps) { const { theme } = useTheme() + const dimensions = useTerminalDimensions() const output = createMemo(() => stripAnsi((stringValue(props.metadata.output) ?? props.output ?? "").trim())) const command = createMemo(() => stringValue(props.input.command) ?? pendingInput(props.part)) const title = createMemo(() => `# ${stringValue(props.input.description) ?? "Shell"}`) const [expanded, setExpanded] = createSignal(false) - const lines = createMemo(() => output().split("\n")) - const overflow = createMemo(() => lines().length > 10) + const maxLines = 10 + const maxChars = createMemo(() => maxLines * Math.max(20, dimensions().width - 6)) + const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars())) const limited = createMemo(() => { - if (expanded() || !overflow()) return output() - return [...lines().slice(0, 10), "…"].join("\n") + if (expanded() || !collapsed().overflow) return output() + return collapsed().output }) return ( @@ -719,12 +723,12 @@ function Bash(props: ToolProps) { title={title()} part={props.part} spinner={props.part.state.status === "running"} - onClick={overflow() ? () => setExpanded((prev) => !prev) : undefined} + onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined} > $ {command()} {limited()} - + {expanded() ? "Click to collapse" : "Click to expand"} diff --git a/packages/opencode/src/cli/cmd/tui/keymap.tsx b/packages/opencode/src/cli/cmd/tui/keymap.tsx index 289bb901d6..2d820c8a23 100644 --- a/packages/opencode/src/cli/cmd/tui/keymap.tsx +++ b/packages/opencode/src/cli/cmd/tui/keymap.tsx @@ -5,30 +5,103 @@ import { formatCommandBindings as formatCommandBindingsExtra, formatKeySequence as formatKeySequenceExtra, } from "@opentui/keymap/extras" -import { - KeymapProvider, - reactiveMatcherFromSignal, - useKeymap, - useKeymapSelector, - useBindings, -} from "@opentui/keymap/solid" -import type { Accessor } from "solid-js" +import { KeymapProvider, useKeymap, useKeymapSelector, useBindings } from "@opentui/keymap/solid" +import { createMemo, type Accessor } from "solid-js" import type { TuiConfig } from "./config/tui" import { useTuiConfig } from "./context/tui-config" import { TuiKeybind } from "./config/keybind" export const LEADER_TOKEN = "leader" +export const KILO_BASE_MODE = "base" +export const COMMAND_PALETTE_COMMAND = "command.palette.show" + +const KILO_MODE_KEY = "opencode.mode" export const OpencodeKeymapProvider = KeymapProvider export const useOpencodeKeymap = useKeymap -export { reactiveMatcherFromSignal, useBindings, useKeymapSelector } +export { useBindings, useKeymapSelector } export type OpenTuiKeymap = ReturnType +type OpencodeModeStack = ReturnType +type CommandSlashEntry = { + display: string + description?: string + aliases?: string[] + onSelect: () => void +} +type Command = ReturnType[number] + +const modeStacks = new WeakMap() + +function isVisiblePaletteCommand(command: Command) { + return command.hidden !== true && command.name !== COMMAND_PALETTE_COMMAND +} + +export function createOpencodeModeStack(keymap: OpenTuiKeymap) { + keymap.setData(KILO_MODE_KEY, KILO_BASE_MODE) + + const offFields = keymap.registerLayerFields({ + mode(value, ctx) { + ctx.require(KILO_MODE_KEY, value) + }, + }) + + const stack: { id: symbol; mode: string }[] = [] + let disposed = false + + const update = () => { + keymap.setData(KILO_MODE_KEY, stack.at(-1)?.mode ?? KILO_BASE_MODE) + } + + const stackApi = { + current() { + return stack.at(-1)?.mode ?? KILO_BASE_MODE + }, + push(mode: string) { + if (disposed) return () => {} + const id = Symbol(mode) + let active = true + stack.push({ id, mode }) + update() + + return () => { + if (!active) return + active = false + const index = stack.findIndex((item) => item.id === id) + if (index !== -1) stack.splice(index, 1) + update() + } + }, + dispose() { + if (disposed) return + disposed = true + stack.length = 0 + offFields() + keymap.setData(KILO_MODE_KEY, undefined) + modeStacks.delete(keymap) + }, + } + + modeStacks.set(keymap, stackApi) + return stackApi +} + +export function useOpencodeModeStack() { + return getOpencodeModeStack(useOpencodeKeymap()) +} + +export function getOpencodeModeStack(keymap: OpenTuiKeymap) { + const value = modeStacks.get(keymap) + if (!value) throw new Error("Opencode mode stack is not registered for this keymap") + return value +} const KEY_ALIASES = { enter: "return", esc: "escape", + pgdown: "pagedown", + pgup: "pageup", } as const function expandKeyAliases(input: string) { @@ -125,6 +198,7 @@ export function registerOpencodeKeymap( renderer: CliRenderer, config: Pick, ) { + const modeStack = createOpencodeModeStack(keymap) const offCommaBindings = addons.registerCommaBindings(keymap) const offAliasExpander = registerKeyAliases(keymap) const offBaseLayout = addons.registerBaseLayoutFallback(keymap) @@ -148,6 +222,7 @@ export function registerOpencodeKeymap( offAliasExpander() offBaseLayout() offCommaBindings() + modeStack.dispose() } } @@ -164,3 +239,35 @@ export function useCommandShortcut(command: string): Accessor { export function useLeaderActive(): Accessor { return useKeymapSelector((keymap: OpenTuiKeymap) => keymap.getPendingSequence()[0]?.tokenName === LEADER_TOKEN) } + +export function useCommandSlashes(): Accessor { + const keymap = useOpencodeKeymap() + const entries = useKeymapSelector((keymap: OpenTuiKeymap) => + keymap.getCommandEntries({ + visibility: "reachable", + namespace: "palette", + filter: isVisiblePaletteCommand, + }), + ) + + return createMemo(() => + entries().flatMap((entry) => { + const slashName = entry.command.slashName + if (typeof slashName !== "string" || !slashName) return [] + const slashAliases = entry.command.slashAliases + return { + display: `/${slashName}`, + description: + typeof entry.command.desc === "string" + ? entry.command.desc + : typeof entry.command.title === "string" + ? entry.command.title + : undefined, + aliases: Array.isArray(slashAliases) + ? slashAliases.filter((alias): alias is string => typeof alias === "string").map((alias) => `/${alias}`) + : undefined, + onSelect: () => keymap.dispatchCommand(entry.command.name), + } + }), + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx index d94a41b6e2..4a22855199 100644 --- a/packages/opencode/src/cli/cmd/tui/plugin/api.tsx +++ b/packages/opencode/src/cli/cmd/tui/plugin/api.tsx @@ -219,6 +219,14 @@ export function createTuiApi(input: Input): TuiPluginApi { }, }, keymap: input.keymap, + mode: { + current() { + return Keymap.getOpencodeModeStack(input.keymap).current() + }, + push(mode) { + return Keymap.getOpencodeModeStack(input.keymap).push(mode) + }, + }, route: { register(list) { return routeRegister(input.routes, list, input.bump) @@ -269,7 +277,6 @@ export function createTuiApi(input: Input): TuiPluginApi { return ( pending: Map + dispose_timeout_ms: number } const log = Log.create({ service: "tui.plugin" }) @@ -191,6 +192,17 @@ function createScopedAttention( } } +function createScopedMode(mode: TuiPluginApi["mode"], scope: PluginScope): TuiPluginApi["mode"] { + return { + current() { + return mode.current() + }, + push(value) { + return scope.track(mode.push(value)) + }, + } +} + type CleanupResult = { type: "ok" } | { type: "error"; error: unknown } | { type: "timeout" } function runCleanup(fn: () => unknown, ms: number): Promise { @@ -394,7 +406,7 @@ async function syncPluginThemes(plugin: PluginEntry) { } } -function createPluginScope(load: PluginLoad, id: string) { +function createPluginScope(load: PluginLoad, id: string, disposeTimeoutMs: number) { const ctrl = new AbortController() let list: { key: symbol; fn: TuiDispose }[] = [] let done = false @@ -436,14 +448,14 @@ function createPluginScope(load: PluginLoad, id: string) { ctrl.abort() const queue = [...list].reverse() list = [] - const until = Date.now() + DISPOSE_TIMEOUT_MS + const until = Date.now() + disposeTimeoutMs for (const item of queue) { const left = until - Date.now() if (left <= 0) { fail("timed out cleaning up tui plugin", { path: load.spec, id, - timeout: DISPOSE_TIMEOUT_MS, + timeout: disposeTimeoutMs, }) break } @@ -454,7 +466,7 @@ function createPluginScope(load: PluginLoad, id: string) { fail("timed out cleaning up tui plugin", { path: load.spec, id, - timeout: DISPOSE_TIMEOUT_MS, + timeout: disposeTimeoutMs, }) break } @@ -523,7 +535,7 @@ async function activatePluginEntry(state: RuntimeState, plugin: PluginEntry, per if (persist) writePluginEnabledState(state.api, plugin.id, true) if (plugin.scope) return true - const scope = createPluginScope(plugin.load, plugin.id) + const scope = createPluginScope(plugin.load, plugin.id, state.dispose_timeout_ms) const api = pluginApi(state, plugin, scope, plugin.id) const ok = await Promise.resolve() .then(async () => { @@ -615,6 +627,7 @@ function pluginApi(runtime: RuntimeState, plugin: PluginEntry, scope: PluginScop command: createCommandShim(keymap, api.ui.dialog, api.tuiConfig.keybinds), keys: api.keys, keymap, + mode: createScopedMode(api.mode, scope), route, ui: api.ui, tuiConfig: api.tuiConfig, @@ -1002,7 +1015,12 @@ let loaded: Promise | undefined let runtime: RuntimeState | undefined export const Slot = View -export async function init(input: { api: HostPluginApi; config: TuiConfig.Resolved; dispose?: () => void }) { +export async function init(input: { + api: HostPluginApi + config: TuiConfig.Resolved + dispose?: () => void + disposeTimeoutMs?: number +}) { const cwd = process.cwd() if (loaded) { if (dir !== cwd) { @@ -1052,7 +1070,7 @@ export async function dispose() { state.dispose?.() } -async function load(input: { api: Api; config: TuiConfig.Resolved; dispose?: () => void }) { +async function load(input: { api: Api; config: TuiConfig.Resolved; dispose?: () => void; disposeTimeoutMs?: number }) { const { api, config } = input const cwd = process.cwd() const slots = setupSlots(api) @@ -1064,6 +1082,7 @@ async function load(input: { api: Api; config: TuiConfig.Resolved; dispose?: () plugins: [], plugins_by_id: new Map(), pending: new Map(), + dispose_timeout_ms: input.disposeTimeoutMs ?? DISPOSE_TIMEOUT_MS, } runtime = next try { diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx index 43a52082be..bbdbecf329 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx @@ -1,7 +1,6 @@ import { Prompt, type PromptRef } from "@tui/component/prompt" import { createEffect, createSignal, onMount } from "solid-js" import { Logo } from "../component/logo" -import { useProject } from "../context/project" import { useSync } from "../context/sync" import { Toast } from "../ui/toast" import { useArgs } from "../context/args" @@ -19,7 +18,6 @@ const placeholder = { export function Home() { const sync = useSync() - const project = useProject() const route = useRouteData("home") const promptRef = usePromptRef() const [ref, setRef] = createSignal() @@ -70,18 +68,8 @@ export function Home() { - - } - placeholders={placeholder} - /> + + } placeholders={placeholder} /> diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 5fd1f68433..619045ab2f 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -21,7 +21,7 @@ import { useSync } from "@tui/context/sync" import { useEvent } from "@tui/context/event" import { SplitBorder } from "@tui/component/border" import { Spinner } from "@tui/component/spinner" -import { selectedForeground, useTheme } from "@tui/context/theme" +import { generateSubtleSyntax, selectedForeground, useTheme } from "@tui/context/theme" import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core" import { Prompt, type PromptRef } from "@tui/component/prompt" import type { @@ -53,7 +53,6 @@ import type { SkillTool } from "@/tool/skill" import { useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid" import { useSDK } from "@tui/context/sdk" import { useEditorContext } from "@tui/context/editor" -import type { DialogContext } from "@tui/ui/dialog" import { useDialog } from "../../ui/dialog" import { TodoItem } from "../../component/todo-item" import { DialogMessage } from "./dialog-message" @@ -84,12 +83,12 @@ import { UI } from "@/cli/ui.ts" import { useTuiConfig } from "../../context/tui-config" import { nextThinkingMode, reasoningTitle, useThinkingMode, type ThinkingMode } from "../../context/thinking" import { getScrollAcceleration } from "../../util/scroll" +import { collapseToolOutput } from "../../util/collapse-tool-output" import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime" import { DialogRetryAction } from "../../component/dialog-retry-action" import { SessionRetry } from "@/session/retry" import { getRevertDiffFiles } from "../../util/revert-diff" -import { useCommandPalette } from "../../context/command-palette" -import { useBindings, useCommandShortcut } from "../../keymap" +import { KILO_BASE_MODE, useBindings, useCommandShortcut, useOpencodeKeymap } from "../../keymap" import { PathFormatterProvider, usePathFormatter } from "../../context/path-format" addDefaultParsers(parsers.parsers) @@ -310,7 +309,7 @@ export function Session() { seeded = true r.set(route.prompt) } - const command = useCommandPalette() + const keymap = useOpencodeKeymap() const dialog = useDialog() const renderer = useRenderer() @@ -1055,7 +1054,7 @@ export function Session() { })) useBindings(() => ({ - enabled: command.matcher, + mode: KILO_BASE_MODE, bindings: tuiConfig.keybinds.gather("session", sessionBindingCommands), })) @@ -1132,7 +1131,6 @@ export function Session() { {(function () { - const command = useCommandPalette() const redoShortcut = useCommandShortcut("session.redo") const [hover, setHover] = createSignal(false) const dialog = useDialog() @@ -1144,7 +1142,7 @@ export function Session() { "Are you sure you want to restore the reverted messages?", ) if (confirmed) { - command.run("session.redo") + keymap.dispatchCommand("session.redo") } } @@ -1499,7 +1497,7 @@ const PART_MAPPING = { } function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: AssistantMessage }) { - const { theme, subtleSyntax } = useTheme() + const { theme } = useTheme() const ctx = use() // Collapsed by default in hide mode: a single line throughout, so the // layout never shifts. Click to open the full markdown block, click to close. @@ -1521,6 +1519,8 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass // blocks. Surface the title both while streaming and after settling so the // collapsed line carries real signal, not just a duration. const title = createMemo(() => reasoningTitle(content())) + // Keep markdown emphasis for the existing thinking color/concealment, but render it without italics. + const syntax = createMemo(() => generateSubtleSyntax(theme, { "markup.italic": { italic: false } })) const toggle = () => { if (!inMinimal()) return @@ -1532,41 +1532,26 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass {/* Full markdown block: `show` mode, or `hide` after the user opens it. */} - + - {/* Settled: ▶ at the start as the click-to-expand cue. */} - - {"▶ " + - (title() - ? "Thought: " + title() + " · " + Locale.duration(duration()) - : "Thought for " + Locale.duration(duration()))} - + - {/* Streaming: leading animated spinner, no disclosure arrow yet — it - snaps in once reasoning settles, signalling "done, click to expand". */} {title() ? "Thinking: " + title() : "Thinking"} @@ -1576,6 +1561,19 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass ) } +function CollapsedReasoningText(props: { title: string | null; duration: number }) { + const { theme } = useTheme() + const duration = () => Locale.duration(props.duration) + + return ( + + + {props.title ? "+ Thought: " + props.title + " · " + duration() : "+ Thought: " + duration()} + + + ) +} + function TextPart(props: { last: boolean; part: TextPart; message: AssistantMessage }) { const ctx = use() const { theme, syntax } = useTheme() @@ -1696,12 +1694,12 @@ function GenericTool(props: ToolProps) { const ctx = use() const output = createMemo(() => props.output?.trim() ?? "") const [expanded, setExpanded] = createSignal(false) - const lines = createMemo(() => output().split("\n")) const maxLines = 3 - const overflow = createMemo(() => lines().length > maxLines) + const maxChars = createMemo(() => maxLines * Math.max(20, ctx.width - 6)) + const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars())) const limited = createMemo(() => { - if (expanded() || !overflow()) return output() - return [...lines().slice(0, maxLines), "…"].join("\n") + if (expanded() || !collapsed().overflow) return output() + return collapsed().output }) return ( @@ -1716,11 +1714,11 @@ function GenericTool(props: ToolProps) { setExpanded((prev) => !prev) : undefined} + onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined} > {limited()} - + {expanded() ? "Click to collapse" : "Click to expand"} @@ -1871,14 +1869,16 @@ function BlockTool(props: { function Shell(props: ToolProps) { const { theme } = useTheme() const pathFormatter = usePathFormatter() + const ctx = use() const isRunning = createMemo(() => props.part.state.status === "running") const output = createMemo(() => stripAnsi(props.metadata.output?.trim() ?? "")) const [expanded, setExpanded] = createSignal(false) - const lines = createMemo(() => output().split("\n")) - const overflow = createMemo(() => lines().length > 10) + const maxLines = 10 + const maxChars = createMemo(() => maxLines * Math.max(20, ctx.width - 6)) + const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars())) const limited = createMemo(() => { - if (expanded() || !overflow()) return output() - return [...lines().slice(0, 10), "…"].join("\n") + if (expanded() || !collapsed().overflow) return output() + return collapsed().output }) const workdirDisplay = createMemo(() => { @@ -1902,14 +1902,14 @@ function Shell(props: ToolProps) { title={title()} part={props.part} spinner={isRunning()} - onClick={overflow() ? () => setExpanded((prev) => !prev) : undefined} + onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined} > $ {props.input.command} {limited()} - + {expanded() ? "Click to collapse" : "Click to expand"} diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx index 526dd30f3b..161a9a6b90 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -1,5 +1,5 @@ import { createStore } from "solid-js/store" -import { createMemo, createSignal, For, Match, Show, Switch } from "solid-js" +import { createMemo, For, Match, Show, Switch } from "solid-js" import { Portal, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid" import type { TextareaRenderable } from "@opentui/core" import { useTheme, selectedForeground } from "../../context/theme" @@ -13,10 +13,9 @@ import { LANGUAGE_EXTENSIONS } from "@/lsp/language" import { Locale } from "@/util/locale" import { ShellID } from "@/tool/shell/id" import { webSearchProviderLabel } from "@/tool/websearch" -import { useDialog } from "../../ui/dialog" import { getScrollAcceleration } from "../../util/scroll" import { useTuiConfig } from "../../context/tui-config" -import { useBindings, useCommandShortcut } from "../../keymap" +import { KILO_BASE_MODE, useBindings, useCommandShortcut } from "../../keymap" import { usePathFormatter } from "../../context/path-format" type PermissionStage = "permission" | "always" | "reject" @@ -448,9 +447,8 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: ( const tuiConfig = useTuiConfig() const dimensions = useTerminalDimensions() const narrow = createMemo(() => dimensions().width < 80) - const dialog = useDialog() useBindings(() => ({ - enabled: dialog.stack.length === 0, + mode: KILO_BASE_MODE, commands: [ { name: "app.exit", @@ -542,11 +540,10 @@ function Prompt>(props: { expanded: false, }) const narrow = createMemo(() => dimensions().width < 80) - const dialog = useDialog() const fullscreenHint = useCommandShortcut("permission.prompt.fullscreen") useBindings(() => ({ - enabled: dialog.stack.length === 0, + mode: KILO_BASE_MODE, commands: [ { name: "app.exit", diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx index a23e267c7a..4b8f1e3ec8 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/question.tsx @@ -1,20 +1,22 @@ import { createStore } from "solid-js/store" -import { createMemo, createSignal, For, Show } from "solid-js" +import { createMemo, createSignal, For, onCleanup, onMount, Show } from "solid-js" import { useRenderer } from "@opentui/solid" import type { TextareaRenderable } from "@opentui/core" import { selectedForeground, tint, useTheme } from "../../context/theme" import type { QuestionAnswer, QuestionRequest } from "@kilocode/sdk/v2" import { useSDK } from "../../context/sdk" import { SplitBorder } from "../../component/border" -import { useDialog } from "../../ui/dialog" import { useTuiConfig } from "../../context/tui-config" -import { useBindings } from "../../keymap" +import { useBindings, useOpencodeModeStack } from "../../keymap" + +const QUESTION_MODE = "question" export function QuestionPrompt(props: { request: QuestionRequest }) { const sdk = useSDK() const { theme } = useTheme() const renderer = useRenderer() const tuiConfig = useTuiConfig() + const modeStack = useOpencodeModeStack() const questions = createMemo(() => props.request.questions) const single = createMemo(() => questions().length === 1 && questions()[0]?.multiple !== true) @@ -120,9 +122,13 @@ export function QuestionPrompt(props: { request: QuestionRequest }) { pick(opt.label) } - const dialog = useDialog() + onMount(() => { + const popMode = modeStack.push(QUESTION_MODE) + onCleanup(popMode) + }) useBindings(() => ({ + mode: QUESTION_MODE, enabled: store.editing && !confirm(), commands: [ { @@ -203,7 +209,8 @@ export function QuestionPrompt(props: { request: QuestionRequest }) { const max = Math.min(total, 9) return { - enabled: dialog.stack.length === 0 && !store.editing, + mode: QUESTION_MODE, + enabled: !store.editing, commands: [ { name: "app.exit", @@ -376,7 +383,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) { - {picked() ? "✓" : ""} + {picked() ? " ✓" : ""} @@ -409,7 +416,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) { - {customPicked() ? "✓" : ""} + {customPicked() ? " ✓" : ""} diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx index c7cd2b0f04..82e114caf1 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx @@ -6,8 +6,7 @@ import { SplitBorder } from "@tui/component/border" import type { AssistantMessage } from "@kilocode/sdk/v2" import { Locale } from "@/util/locale" import { useTerminalDimensions } from "@opentui/solid" -import { useCommandPalette } from "../../context/command-palette" -import { useCommandShortcut } from "../../keymap" +import { useCommandShortcut, useOpencodeKeymap } from "../../keymap" export function SubagentFooter() { const route = useRouteData("session") @@ -56,7 +55,7 @@ export function SubagentFooter() { }) const { theme } = useTheme() - const command = useCommandPalette() + const keymap = useOpencodeKeymap() const parentShortcut = useCommandShortcut("session.parent") const previousShortcut = useCommandShortcut("session.child.previous") const nextShortcut = useCommandShortcut("session.child.next") @@ -98,7 +97,7 @@ export function SubagentFooter() { setHover("parent")} onMouseOut={() => setHover(null)} - onMouseUp={() => command.run("session.parent")} + onMouseUp={() => keymap.dispatchCommand("session.parent")} backgroundColor={hover() === "parent" ? theme.backgroundElement : theme.backgroundPanel} > @@ -108,7 +107,7 @@ export function SubagentFooter() { setHover("prev")} onMouseOut={() => setHover(null)} - onMouseUp={() => command.run("session.child.previous")} + onMouseUp={() => keymap.dispatchCommand("session.child.previous")} backgroundColor={hover() === "prev" ? theme.backgroundElement : theme.backgroundPanel} > @@ -118,7 +117,7 @@ export function SubagentFooter() { setHover("next")} onMouseOut={() => setHover(null)} - onMouseUp={() => command.run("session.child.next")} + onMouseUp={() => keymap.dispatchCommand("session.child.next")} backgroundColor={hover() === "next" ? theme.backgroundElement : theme.backgroundPanel} > diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx index 34ab9161f6..dfd8091852 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx @@ -1,8 +1,10 @@ import { TextareaRenderable, TextAttributes } from "@opentui/core" import { useTheme } from "../context/theme" import { useDialog, type DialogContext } from "./dialog" -import { Show, createEffect, onMount, type JSX } from "solid-js" +import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js" import { Spinner } from "../component/spinner" +import { useTuiConfig } from "../context/tui-config" +import { useBindings, useCommandShortcut } from "../keymap" export type DialogPromptProps = { title: string @@ -18,8 +20,32 @@ export type DialogPromptProps = { export function DialogPrompt(props: DialogPromptProps) { const dialog = useDialog() const { theme } = useTheme() + const tuiConfig = useTuiConfig() + const submitShortcut = useCommandShortcut("dialog.prompt.submit") + const [textareaTarget, setTextareaTarget] = createSignal() let textarea: TextareaRenderable + function confirm() { + if (props.busy) return + props.onConfirm?.(textarea.plainText) + } + + useBindings(() => ({ + target: textareaTarget, + enabled: textareaTarget() !== undefined && !props.busy, + // Dialog form semantics must win over the global managed textarea input layer. + priority: 1, + commands: [ + { + name: "dialog.prompt.submit", + title: "Submit dialog prompt", + category: "Dialog", + run: confirm, + }, + ], + bindings: tuiConfig.keybinds.gather("dialog.prompt", ["dialog.prompt.submit"]), + })) + onMount(() => { dialog.setSize("medium") setTimeout(() => { @@ -59,13 +85,10 @@ export function DialogPrompt(props: DialogPromptProps) { {props.description}